Apache Zeta Components Manual :: File Source for memory.php

Source for file memory.php

Documentation is available at memory.php

  1. <?php
  2. /**
  3.  * File containing the ezcCacheStorageMemory class.
  4.  *
  5.  * Licensed to the Apache Software Foundation (ASF) under one
  6.  * or more contributor license agreements.  See the NOTICE file
  7.  * distributed with this work for additional information
  8.  * regarding copyright ownership.  The ASF licenses this file
  9.  * to you under the Apache License, Version 2.0 (the
  10.  * "License"); you may not use this file except in compliance
  11.  * with the License.  You may obtain a copy of the License at
  12.  * 
  13.  *   http://www.apache.org/licenses/LICENSE-2.0
  14.  * 
  15.  * Unless required by applicable law or agreed to in writing,
  16.  * software distributed under the License is distributed on an
  17.  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  18.  * KIND, either express or implied.  See the License for the
  19.  * specific language governing permissions and limitations
  20.  * under the License.
  21.  *
  22.  * @package Cache
  23.  * @version //autogentag//
  24.  * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
  25.  * @filesource
  26.  */
  27.  
  28. /**
  29.  * Base abstract class for all memory storage classes.
  30.  *
  31.  * Abstract classes extending this class:
  32.  *  - {@link ezcCacheStorageMemcache}
  33.  *  - {@link ezcCacheStorageApc}
  34.  *
  35.  * Implementations derived from this class and its descendants:
  36.  *  - {@link ezcCacheStorageMemcachePlain}
  37.  *  - {@link ezcCacheStorageApcPlain}
  38.  *  - {@link ezcCacheStorageFileApcArray}
  39.  *
  40.  * @package Cache
  41.  * @version //autogentag//
  42.  */
  43. {
  44.     /**
  45.      * Holds the memory backend object which communicates with the memory handler
  46.      * (Memcache, APC).
  47.      *
  48.      * @var ezcCacheMemoryBackend 
  49.      */
  50.     protected $backend;
  51.  
  52.     /**
  53.      * Holds the name of the memory backend.
  54.      *
  55.      * @var string 
  56.      */
  57.     protected $backendName;
  58.  
  59.     /**
  60.      * Holds the name of the registry.
  61.      *
  62.      * @var string 
  63.      */
  64.     protected $registryName;
  65.  
  66.     /**
  67.      * Holds the registry.
  68.      *
  69.      * @var array(mixed) 
  70.      */
  71.     protected $registry = array();
  72.  
  73.     /**
  74.      * Holds the search registry.
  75.      *
  76.      * @var array(mixed) 
  77.      */
  78.     protected $searchRegistry = array();
  79.  
  80.     /**
  81.      * Wether this storage holds a lock.
  82.      * 
  83.      * @var bool 
  84.      */
  85.     private $lock false;
  86.  
  87.     /**
  88.      * Creates a new cache storage in the given location.
  89.      *
  90.      * Options can contain the 'ttl' (Time-To-Live). Specific implementations
  91.      * can have additional options.
  92.      *
  93.      * @throws ezcBasePropertyNotFoundException
  94.      *          If you tried to set a non-existent option value. The accepted
  95.      *          options depend on the ezcCacheStorage implementation and may
  96.      *          vary.
  97.      *
  98.      * @param string $location Path to the cache location. Null for
  99.      *                          memory-based storage and an existing
  100.      *                          writeable path for file or memory/file
  101.      *                          storage.
  102.      * @param array(string=>string) $options Options for the cache
  103.      */
  104.     public function __construct$locationarray $options array() )
  105.     {
  106.         parent::__construct$locationarray() );
  107.     }
  108.  
  109.     /**
  110.      * Stores data to the cache storage under the key $id.
  111.      *
  112.      * The type of cache data which is expected by an ezcCacheStorageMemory
  113.      * implementation depends on the backend. In most cases strings and arrays
  114.      * will be accepted, in some rare cases only strings might be accepted.
  115.      *
  116.      * Using attributes you can describe your cache data further. This allows
  117.      * you to deal with multiple cache data at once later. Some
  118.      * ezcCacheStorageMemory implementations also use the attributes for storage
  119.      * purposes. Attributes form some kind of "extended ID".
  120.      *
  121.      * @return string The ID string of the newly cached data
  122.      *
  123.      * @param string $id Unique identifier for the data
  124.      * @param mixed $data The data to store
  125.      * @param array(string=>string) $attributes Attributes describing the cached data
  126.      */
  127.     public function store$id$data$attributes array() )
  128.     {
  129.         // Generate the Identifier
  130.         $identifier $this->generateIdentifier$id$attributes );
  131.         $location $this->properties['location'];
  132.  
  133.         if isset$this->registry[$location][$id][$identifier) )
  134.         {
  135.             unset$this->registry[$location][$id][$identifier);
  136.         }
  137.  
  138.         // Prepare the data
  139.         $dataStr $this->prepareData$data );
  140.  
  141.         // Store the data
  142.         $this->registerIdentifier$id$attributes$identifier );
  143.         if !$this->backend->store$identifier$dataStr$this->properties['options']['ttl') )
  144.         {
  145.             $exceptionClass "ezcCache{$this->backendName}Exception";
  146.             throw new $exceptionClass( "{$this->backendName} store failed." );
  147.         }
  148.  
  149.         return $id;
  150.     }
  151.  
  152.     /**
  153.      * Restores the data from the cache.
  154.      *
  155.      * During access to cached data the caches are automatically
  156.      * expired. This means, that the ezcCacheStorageMemory object checks
  157.      * before returning the data if it's still actual. If the cache
  158.      * has expired, data will be deleted and false is returned.
  159.      *
  160.      * You should always provide the attributes you assigned, although
  161.      * the cache storages must be able to find a cache ID even without
  162.      * them. BEWARE: Finding cache data only by ID can be much
  163.      * slower than finding it by ID and attributes.
  164.      *
  165.      * @param string $id The item ID to restore
  166.      * @param array(string=>string) $attributes Attributes describing the data to restore
  167.      * @param bool $search Whether to search for items if not found directly
  168.      * @return mixed The cached data on success, otherwise false
  169.      */
  170.     public function restore( $id, $attributes = array(), $search = false )
  171.     {
  172.         // Generate the Identifier
  173.         $identifier = $this->generateIdentifier$id$attributes );
  174.         $location $this->properties['location'];
  175.  
  176.         // Creates a registry object
  177.         if !isset$this->registry[$location][$id][$identifier) )
  178.         {
  179.             if ( !isset( $this->registry[$location) )
  180.             {
  181.                 $this->registry[$locationarray();
  182.             }
  183.             if ( !isset( $this->registry[$location][$id) )
  184.             {
  185.                 $this->registry[$location][$idarray();
  186.             }
  187.             $this->registry[$location][$id][$identifier$this->fetchData$identifiertrue );
  188.         }
  189.  
  190.         // Makes sure a cache exists
  191.         if ( $this->registry[$location][$id][$identifier=== false )
  192.         {
  193.             if ( $search === true
  194.                  && count( $identifiers = $this->search$id$attributes ) ) === )
  195.             {
  196.                 $identifier = $identifiers[0][2];
  197.                 $this->registry[$location][$id][$identifier$this->fetchData$identifiertrue );
  198.             }
  199.             else
  200.             {
  201.                 // There are more elements found during search, so false is returned
  202.                 return false;
  203.             }
  204.         }
  205.  
  206.         // Make sure the data is not supposed to be expired
  207.         if ( $this->properties['options']['ttl'!== false 
  208.              && $this->calcLifetime$identifier$this->registry[$location][$id][$identifier== )
  209.         {
  210.             $this->delete$id$attributesfalse );
  211.             return false;
  212.         }
  213.  
  214.         // Return the data
  215.         $data = is_object( $this->registry[$location][$id][$identifier$this->registry[$location][$id][$identifier]->data false;
  216.         if $data !== false )
  217.         {
  218.             return $data;
  219.         }
  220.         else
  221.         {
  222.             return false;
  223.         }
  224.     }
  225.  
  226.     /**
  227.      * Deletes the data associated with $id or $attributes from the cache.
  228.      *
  229.      * Additional attributes provided will matched additionally. This can give
  230.      * you an immense speed improvement against just searching for ID (see
  231.      * {@link ezcCacheStorage::restore()}).
  232.      *
  233.      * If you only provide attributes for deletion of cache data, all cache
  234.      * data matching these attributes will be purged.
  235.      *
  236.      * @throws ezcBaseFilePermissionException
  237.      *         If an already existsing cache file could not be unlinked.
  238.      *         This exception means most likely that your cache directory
  239.      *         has been corrupted by external influences (file permission
  240.      *         change).
  241.      *
  242.      * @param string $id The item ID to purge
  243.      * @param array(string=>string) $attributes Attributes describing the data to restore
  244.      * @param bool $search Whether to search for items if not found directly
  245.      */
  246.     public function delete( $id = null, $attributes = array(), $search = false )
  247.     {
  248.         // Generate the Identifier
  249.         $identifier = $this->generateIdentifier$id$attributes );
  250.         $location $this->properties['location'];
  251.  
  252.         // Finds the caches that require deletion
  253.         $delCaches array();
  254.         if $this->fetchData$identifier !== false )
  255.         {
  256.             $delCaches[] = array( $id, $attributes, $identifier );
  257.         }
  258.         else if ( $search === true )
  259.         {
  260.             $delCaches = $this->search$id$attributes );
  261.         }
  262.  
  263.         $deletedIds = array();
  264.  
  265.         // Process the caches to delete
  266.         $identifiers = array();
  267.         foreach ( $delCaches as $cache )
  268.         {
  269.             $this->backend->delete$cache[2);
  270.             $deletedIds[$cache[0];
  271.             $this->unRegisterIdentifier$cache[0]$cache[1]$cache[2]true );
  272.             if isset$this->registry[$location][$cache[0]][$cache[2]] ) )
  273.             {
  274.                 unset( $this->registry[$location][$cache[0]][$cache[2]] );
  275.             }
  276.         }
  277.         $this->storeSearchRegistry();
  278.  
  279.         return $deletedIds;
  280.     }
  281.  
  282.     /**
  283.      * Returns the number of items in the cache matching a certain criteria.
  284.      *
  285.      * This method determines if cache data described by the given ID and/or
  286.      * attributes exists. It returns the number of cache data items found.
  287.      *
  288.      * @param string $id The item ID
  289.      * @param array(string=>string) $attributes Attributes describing the data
  290.      * @return int Number of data items matching the criteria
  291.      */
  292.     public function countDataItems( $id = null, $attributes = array() )
  293.     {
  294.         return count( $this->search$id$attributes ) );
  295.     }
  296.  
  297.     /**
  298.      * Returns the time in seconds which remains for a cache object, before it
  299.      * gets outdated. In case the cache object is already outdated or does not
  300.      * exists, this method returns 0.
  301.      *
  302.      * @param string $id The item ID
  303.      * @param array(string=>string) $attributes Attributes describing the data
  304.      * @return int The remaining lifetime (0 if it does not exist or outdated)
  305.      */
  306.     public function getRemainingLifetime( $id, $attributes = array() )
  307.     {
  308.         if ( count( $found = $this->search$id$attributes ) ) 
  309.         {
  310.             $identifier = $found[0][2];
  311.             return $this->calcLifetime$identifier );
  312.         }
  313.         return 0;
  314.     }
  315.  
  316.     /**
  317.      * Generates the storage internal identifier from ID and attributes.
  318.      *
  319.      * @param string $id The ID
  320.      * @param array(string=>string) $attributes Attributes describing the data
  321.      * @return string The generated identifier
  322.      */
  323.     public function generateIdentifier( $id, $attributes = null )
  324.     {
  325.         $identifier = strtolower( $this->backendName )
  326.             . $this->properties['location']
  327.             . $id 
  328.             . (
  329.                 $attributes !== null && !empty$attributes ) ) 
  330.                 ? md5serialize$attributes ) ) 
  331.                 : ''
  332.         );
  333.         return urlencode$identifier );
  334.     }
  335.  
  336.     /**
  337.      * Purge outdated data from the storage. 
  338.      * 
  339.      * This method purges outdated data from the cache. If $limit is given, a
  340.      * maximum of $limit items is purged. Otherwise all outdated items are
  341.      * purged. The method returns an array containing the IDs of all cache
  342.      * items that have been purged.
  343.      *
  344.      * @param int $limit 
  345.      * @return array(string)
  346.      */
  347.     public function purge( $limit = null )
  348.     {
  349.         $this->fetchSearchRegistrytrue );
  350.  
  351.         $purgedIds array();
  352.         $ttl       $this->properties['options']->ttl;
  353.  
  354.         foreach $this->searchRegistry[$this->properties['location']] as $id => $identifiers )
  355.         {
  356.             $deleted = false;
  357.             foreach( $identifiers as $identifier => $data )
  358.             {
  359.                 if ( $ttl !== false && $this->calcLifetime$identifier == )
  360.                 {
  361.                     // Since ID <-> identifier mapping is ambigious, this does
  362.                     // not ensure that all data for an ID is deleted. However,
  363.                     // this should work if used properly
  364.                     $this->backend->delete$identifier );
  365.                     $this->unRegisterIdentifiernullnull$identifierstrue );
  366.                     // Avoid adding an ID twice to the returned array
  367.                     $deleted true;
  368.                 }
  369.             }
  370.             if ( $deleted === true )
  371.             {
  372.                 $purgedIds[] = $id;
  373.             }
  374.             if ( $limit !== null && count( $purgedIds ) >= $limit )
  375.             {
  376.                 break;
  377.             }
  378.         }
  379.         $this->storeSearchRegistry();
  380.         return $purgedIds;
  381.     }
  382.  
  383.     /**
  384.      * Reset the complete storage.
  385.      *
  386.      * This method resets the complete cache storage. All content (including
  387.      * content stored with the {@link ezcCacheStackMetaDataStorage} interfacer) must
  388.      * be deleted and the cache storage must appear as if it has just newly
  389.      * been created.
  390.      * 
  391.      * @return void
  392.      */
  393.     public function reset()
  394.     {
  395.         $this->backend->reset();
  396.         $this->registry = array();
  397.         $this->searchRegistry = array$this->properties['location'=> null );
  398.         $this->storeSearchRegistry();
  399.     }
  400.     
  401.     /**
  402.      * Restores and returns the meta data struct.
  403.      *
  404.      * This method fetches the meta data stored in the storage and returns the
  405.      * according struct of type {@link ezcCacheStackMetaData}. The meta data
  406.      * must be stored inside the storage, but should not be visible as normal
  407.      * cache items to the user.
  408.      * 
  409.      * @return ezcCacheStackMetaData
  410.      */
  411.     public function restoreMetaData()
  412.     {
  413.         $metaDataKey = urlencode( $this->properties['location''_'
  414.             . $this->properties['options']->metaDataKey;
  415.  
  416.         if ( ( $data $this->backend->fetch$metaDataKey ) ) === false )
  417.         {
  418.             $data = null;
  419.         }
  420.         return $data;
  421.     }
  422.  
  423.     /**
  424.      * Stores the given meta data struct.
  425.      *
  426.      * This method stores the given $metaData inside the storage. The data must
  427.      * be stored with the same mechanism that the storage itself uses. However,
  428.      * it should not be stored as a normal cache item, if possible, to avoid
  429.      * accedental user manipulation.
  430.      * 
  431.      * @param ezcCacheStackMetaData $metaData 
  432.      * @return void
  433.      */
  434.     public function storeMetaData( ezcCacheStackMetaData $metaData )
  435.     {
  436.         $metaDataKey = urlencode( $this->properties['location''_'
  437.             . $this->properties['options']->metaDataKey;
  438.  
  439.         $this->backend->store(
  440.             $metaDataKey,
  441.             $metaData
  442.         );
  443.     }
  444.  
  445.     /**
  446.      * Acquire a lock on the storage.
  447.      *
  448.      * This method acquires a lock on the storage. If locked, the storage must
  449.      * block all other method calls until the lock is freed again using {@link
  450.      * ezcCacheStackMetaDataStorage::unlock()}. Methods that are called within
  451.      * the request that successfully acquired the lock must succeed as usual.
  452.      * 
  453.      * @return void
  454.      */
  455.     public function lock()
  456.     {
  457.         $lockKey = urlencode( $this->properties['location''_'
  458.             . $this->properties['options']->lockKey;
  459.         $this->backend->acquireLock(
  460.             $lockKey,
  461.             $this->properties['options']->lockWaitTime,
  462.             $this->properties['options']->maxLockTime
  463.         );
  464.         $this->lock true;
  465.     }
  466.  
  467.     /**
  468.      * Release a lock on the storage.
  469.      *
  470.      * This method releases the lock of the storage, that has been acquired via
  471.      * {@link ezcCacheStackMetaDataStorage::lock()}. After this method has been
  472.      * called, blocked method calls (including calls to lock()) can suceed
  473.      * again.
  474.      * 
  475.      * @return void
  476.      */
  477.     public function unlock()
  478.     {
  479.         if ( $this->lock !== false )
  480.         {
  481.             $lockKey = urlencode( $this->properties['location''_'
  482.                 . $this->properties['options']->lockKey;
  483.             $this->backend->releaseLock(
  484.                 $lockKey
  485.             );
  486.             $this->lock false;
  487.         }
  488.     }
  489.  
  490.     /**
  491.      * Calculates the lifetime remaining for a cache object.
  492.      *
  493.      * In case the TTL options is set to true, this method always returns 1.
  494.      *
  495.      * @param string $identifier The memcache identifier
  496.      * @param bool $dataObject The optional data object for which to calculate the lifetime
  497.      * @return int The remaining lifetime in seconds (0 if no time remaining)
  498.      */
  499.     protected function calcLifetime( $identifier, $dataObject = false )
  500.     {
  501.         $ttl = $this->options->ttl;
  502.         $dataObject is_object$dataObject $dataObject $this->fetchData $identifiertrue );
  503.         if is_object$dataObject ) )
  504.         {
  505.             if ( $ttl === false )
  506.             {
  507.                 return 1;
  508.             }
  509.             return (
  510.                 ( $lifeTime = ( time() - $dataObject->time $ttl 
  511.                     ? $ttl $lifeTime
  512.                     : 0
  513.             );
  514.         }
  515.         else
  516.         {
  517.             return 0;
  518.         }
  519.     }
  520.  
  521.     /**
  522.      * Registers an identifier to facilitate searching.
  523.      *
  524.      * @param string $id ID for the cache item
  525.      * @param array $attributes Attributes for the cache item
  526.      * @param string $identifier Identifier generated for the cache item
  527.      */
  528.     protected function registerIdentifier( $id = null, $attributes = array(), $identifier = null )
  529.     {
  530.         $identifier = ( $identifier !== null ) ? $identifier : $this->generateIdentifier$id$attributes );
  531.         $location $this->properties['location'];
  532.  
  533.         $this->fetchSearchRegistry();
  534.  
  535.         // Makes sure the identifier exists
  536.         if !isset$this->searchRegistry[$location][$id][$identifier) )
  537.         {
  538.             // Makes sure the id exists
  539.             if ( !isset( $this->searchRegistry[$location][$id)
  540.                  || !is_array$this->searchRegistry[$location][$id) )
  541.             {
  542.                 $this->searchRegistry[$location][$idarray();
  543.             }
  544.  
  545.             $this->searchRegistry[$location][$id][$identifiernew ezcCacheStorageMemoryRegisterStruct$id$attributes$identifier$location );
  546.             $this->storeSearchRegistry();
  547.         }
  548.     }
  549.  
  550.     /**
  551.      * Un-registers a previously registered identifier.
  552.      *
  553.      * @param string $id ID for the cache item
  554.      * @param array $attributes Attributes for the cache item
  555.      * @param string $identifier Identifier generated for the cache item
  556.      * @param bool $delayStore Delays the storing of the updated search registry
  557.      */
  558.     protected function unRegisterIdentifier( $id = null, $attributes = array(), $identifier = null, $delayStore = false )
  559.     {
  560.         $identifier = ( $identifier !== null ) ? $identifier : $this->generateIdentifier$id$attributes );
  561.         $location $this->properties['location'];
  562.  
  563.         $this->fetchSearchRegistry!$delayStore );
  564.  
  565.         if $this->searchRegistry === false )
  566.         {
  567.             $this->searchRegistry = array();
  568.         }
  569.  
  570.         if ( isset( $this->searchRegistry[$location][$id][$identifier) )
  571.         {
  572.             unset( $this->searchRegistry[$location][$id][$identifier]$this->registry[$location][$id][$identifier);
  573.             if $delayStore === false )
  574.             {
  575.                 $this->storeSearchRegistry();
  576.             }
  577.         }
  578.     }
  579.  
  580.     /**
  581.      * Fetches the search registry from the backend or creates it if empty.
  582.      *
  583.      * @param bool $requireFresh To create a new search registry or not
  584.      */
  585.     protected function fetchSearchRegistry( $requireFresh = false )
  586.     {
  587.         $location = $this->properties['location'];
  588.         if !is_array$this->searchRegistry ) )
  589.         {
  590.             $this->searchRegistry = array();
  591.         }
  592.         if ( !isset( $this->searchRegistry[$location)
  593.              || !is_array$this->searchRegistry[$location) )
  594.         {
  595.             $this->searchRegistry[$locationarray();
  596.         }
  597.  
  598.         // Makes sure the registry exists
  599.         if ( empty( $this->searchRegistry[$location)
  600.              || $requireFresh === true )
  601.         {
  602.             $this->searchRegistry[$location$this->backend->fetch$this->registryName . '_' urlencode$location ) );
  603.         }
  604.     }
  605.  
  606.     /**
  607.      * Stores the search registry in the backend.
  608.      */
  609.     protected function storeSearchRegistry()
  610.     {
  611.         $location = $this->properties['location'];
  612.  
  613.         $this->backend->store$this->registryName . '_' urlencode$location )$this->searchRegistry[$location);
  614.  
  615.         $this->searchRegistry[$locationnull;
  616.         $this->fetchSearchRegistrytrue );
  617.     }
  618.  
  619.     /**
  620.      * Generates a string from the $attributes array.
  621.      *
  622.      * @param array(string=>string) $attributes Attributes describing the data
  623.      * @return string
  624.      *
  625.      * @apichange Was only used to generate "pseudo-regex". Attribute arrays
  626.      *            are compared directly now.
  627.      */
  628.     protected function generateAttrStr( $attributes = array() )
  629.     {
  630.         ksort( $attributes );
  631.         $attrStr = '';
  632.         foreach ( $attributes as $key => $val )
  633.         {
  634.             $attrStr .= '-' . $key . '=' .$val;
  635.         }
  636.         return $attrStr;
  637.     }
  638.  
  639.     /**
  640.      * Checks if the location property is valid.
  641.      */
  642.     protected function validateLocation()
  643.     {
  644.         return;
  645.     }
  646.  
  647.     /**
  648.      * Searches the storage for data defined by ID and/or attributes.
  649.      *
  650.      * @param string $id The item ID
  651.      * @param array(string=>string) $attributes Attributes describing the data
  652.      * @return array(mixed)
  653.      */
  654.     protected function search( $id = null, $attributes = array() )
  655.     {
  656.         // Grabs the identifier registry
  657.         $this->fetchSearchRegistry();
  658.  
  659.         // Grabs the $location
  660.         $location $this->properties['location'];
  661.  
  662.         // Finds all in case of empty $id and $attributes
  663.         if $id === null
  664.              && empty$attributes )
  665.              && isset$this->searchRegistry[$location)
  666.              && is_array$this->searchRegistry[$location) )
  667.         {
  668.             $itemArr = array();
  669.             foreach ( $this->searchRegistry[$locationas $idArr )
  670.             {
  671.                 foreach ( $idArr as $registryObj )
  672.                 {
  673.                     if ( !is_null( $registryObj->id ) )
  674.                     {
  675.                         $itemArr[] = array( $registryObj->id$registryObj->attributes$registryObj->identifier );
  676.                     }
  677.                 }
  678.             }
  679.             return $itemArr;
  680.         }
  681.  
  682.         $itemArr = array();
  683.         // Makes sure we've seen this ID before
  684.         if ( isset( $this->searchRegistry[$location][$id)
  685.              && is_array$this->searchRegistry[$location][$id) )
  686.         {
  687.             foreach ( $this->searchRegistry[$location][$idas $identifier => $dataArr )
  688.             {
  689.                 if ( $this->fetchData$identifier !== false )
  690.                 {
  691.                     $itemArr[] = array( $id, $attributes, $identifier );
  692.                 }
  693.             }
  694.         }
  695.         else
  696.         {
  697.             // Finds cache items that fit our description
  698.             if ( isset( $this->searchRegistry[$location)
  699.                  && is_array$this->searchRegistry[$location) )
  700.             {
  701.                 foreach ( $this->searchRegistry[$locationas $id => $arr )
  702.                 {
  703.                     foreach ( $arr as $identifier => $registryObj )
  704.                     {
  705.                         if ( count( array_diff_assoc( $attributes, $registryObj->attributes ) ) === )
  706.                         {
  707.                             $itemArr[] = array(
  708.                                 $registryObj->id,
  709.                                 $registryObj->attributes,
  710.                                 $registryObj->identifier
  711.                             );
  712.                         }
  713.                     }
  714.                 }
  715.             }
  716.         }
  717.         return $itemArr;
  718.     }
  719. }
Documentation generated by phpDocumentor 1.4.3