Verzeichnisstruktur phpBB-3.3.15


Veröffentlicht
28.08.2024

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: 02.04.2025, 15:02 - Dateigröße: 6.71 KiB


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