Verzeichnisstruktur phpBB-3.2.0


Veröffentlicht
06.01.2017

So funktioniert es


Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück

Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis.
Auf den Verzeichnisnamen klicken, dies zeigt nur das Verzeichnis mit Inhalt an

(Beispiel Datei-Icons)

Auf das Icon klicken um den Quellcode anzuzeigen

lazy-loading-value-holder.md

Zuletzt modifiziert: 09.10.2024, 12:56 - Dateigröße: 6.40 KiB


001  # Lazy Loading Value Holder Proxy
002   
003  A lazy loading value holder proxy is a virtual proxy that wraps and lazily initializes a "real" instance of the proxied
004  class.
005   
006  ## What is lazy loading?
007   
008  In pseudo-code, in userland, [lazy loading](http://www.martinfowler.com/eaaCatalog/lazyLoad.html) looks like following:
009   
010  ```php
011  class MyObjectProxy
012  {
013      private $wrapped;
014   
015      public function doFoo()
016      {
017          $this->init();
018   
019          return $this->wrapped->doFoo();
020      }
021   
022      private function init()
023      {
024          if (null === $this->wrapped) {
025              $this->wrapped = new MyObject();
026          }
027      }
028  }
029  ```
030   
031  This code is problematic, and adds a lot of complexity that makes your unit tests' code even worse.
032   
033  Also, this kind of usage often ends up in coupling your code with a particular
034  [Dependency Injection Container](http://martinfowler.com/articles/injection.html)
035  or a framework that fetches dependencies for you.
036  That way, further complexity is introduced, and some problems related
037  with service location raise, as I've explained
038  [in this article](http://ocramius.github.com/blog/zf2-and-symfony-service-proxies-with-doctrine-proxies/).
039   
040  Lazy loading value holders abstract this logic for you, hiding your complex, slow, performance-impacting objects behind
041  tiny wrappers that have their same API, and that get initialized at first usage.
042   
043  ## When do I use a lazy value holder?
044   
045  You usually need a lazy value holder in cases where following applies
046   
047   * your object takes a lot of time and memory to be initialized (with all dependencies)
048   * your object is not always used, and the instantiation overhead can be avoided
049   
050  ## Usage examples
051   
052  [ProxyManager](https://github.com/Ocramius/ProxyManager) provides a factory that eases instantiation of lazy loading
053  value holders. To use it, follow these steps:
054   
055  First of all, define your object's logic without taking care of lazy loading:
056   
057  ```php
058  namespace MyApp;
059   
060  class HeavyComplexObject
061  {
062      public function __construct()
063      {
064          // just write your business logic
065          // don't worry about how heavy initialization of this will be!
066      }
067   
068      public function doFoo() {
069          echo "OK!"
070      }
071  }
072  ```
073   
074  Then use the proxy manager to create a lazy version of the object (as a proxy):
075   
076  ```php
077  namespace MyApp;
078   
079  use ProxyManager\Factory\LazyLoadingValueHolderFactory;
080  use ProxyManager\Proxy\LazyLoadingInterface;
081   
082  require_once __DIR__ . '/vendor/autoload.php';
083   
084  $factory     = new LazyLoadingValueHolderFactory();
085  $initializer = function (& $wrappedObject, LazyLoadingInterface $proxy, $method, array $parameters, & $initializer) {
086      $initializer   = null; // disable initialization
087      $wrappedObject = new HeavyComplexObject(); // fill your object with values here
088   
089      return true; // confirm that initialization occurred correctly
090  };
091   
092  $instance = $factory->createProxy('MyApp\HeavyComplexObject', $initializer);
093  ```
094   
095  You can now simply use your object as before:
096   
097  ```php
098  // this will just work as before
099  $proxy->doFoo(); // OK!
100  ```
101   
102  ## Lazy Initialization
103   
104  As you can see, we use a closure to handle lazy initialization of the proxy instance at runtime.
105  The initializer closure signature should be as following:
106   
107  ```php
108  /**
109   * @var object  $wrappedObject the instance (passed by reference) of the wrapped object,
110   *                             set it to your real object
111   * @var object  $proxy         the instance proxy that is being initialized
112   * @var string  $method        the name of the method that triggered lazy initialization
113   * @var string  $parameters    an ordered list of parameters passed to the method that
114   *                             triggered initialization, indexed by parameter name
115   * @var Closure $initializer   a reference to the property that is the initializer for the
116   *                             proxy. Set it to null to disable further initialization
117   *
118   * @return bool true on success
119   */
120  $initializer = function (& $wrappedObject, $proxy, $method, $parameters, & $initializer) {};
121  ```
122   
123  The initializer closure should usually be coded like following:
124   
125  ```php
126  $initializer = function (& $wrappedObject, $proxy, $method, $parameters, & $initializer) {
127      $newlyCreatedObject = new Foo(); // instantiation logic
128      $newlyCreatedObject->setBar('baz') // instantiation logic
129      $newlyCreatedObject->setBat('bam') // instantiation logic
130   
131      $wrappedObject = $newlyCreatedObject; // set wrapped object in the proxy
132      $initializer   = null; // disable initializer
133   
134      return true; // report success
135  };
136  ```
137   
138  The
139  [`ProxyManager\Factory\LazyLoadingValueHolderFactory`](https://github.com/Ocramius/ProxyManager/blob/master/src/ProxyManager/Factory/LazyLoadingValueHolderFactory.php)
140  produces proxies that implement both the
141  [`ProxyManager\Proxy\ValueHolderInterface`](https://github.com/Ocramius/ProxyManager/blob/master/src/ProxyManager/Proxy/ValueHolderInterface.php)
142  and the
143  [`ProxyManager\Proxy\LazyLoadingInterface`](https://github.com/Ocramius/ProxyManager/blob/master/src/ProxyManager/Proxy/LazyLoadingInterface.php).
144   
145  At any point in time, you can set a new initializer for the proxy:
146   
147  ```php
148  $proxy->setProxyInitializer($initializer);
149  ```
150   
151  In your initializer, you currently **MUST** turn off any further initialization:
152   
153  ```php
154  $proxy->setProxyInitializer(null);
155  ```
156   
157  or
158   
159  ```php
160  $initializer = null; // if you use the initializer by reference
161  ```
162   
163  ## Triggering Initialization
164   
165  A lazy loading proxy is initialized whenever you access any property or method of it.
166  Any of the following interactions would trigger lazy initialization:
167   
168  ```php
169  // calling a method
170  $proxy->someMethod();
171   
172  // reading a property
173  echo $proxy->someProperty;
174   
175  // writing a property
176  $proxy->someProperty = 'foo';
177   
178  // checking for existence of a property
179  isset($proxy->someProperty);
180   
181  // removing a property
182  unset($proxy->someProperty);
183   
184  // cloning the entire proxy
185  clone $proxy;
186   
187  // serializing the proxy
188  $unserialized = serialize(unserialize($proxy));
189  ```
190   
191  Remember to call `$proxy->setProxyInitializer(null);` to disable initialization of your proxy, or it will happen more
192  than once.
193   
194  ## Proxying interfaces
195   
196  You can also generate proxies from an interface FQCN. By proxying an interface, you will only be able to access the
197  methods defined by the interface itself, even if the `wrappedObject` implements more methods. This will anyway save
198  some memory since the proxy won't contain useless inherited properties.
199   
200  ## Tuning performance for production
201   
202  See [Tuning ProxyManager for Production](https://github.com/Ocramius/ProxyManager/blob/master/docs/tuning-for-production.md).
203