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. |
|
(Beispiel Datei-Icons)
|
Auf das Icon klicken um den Quellcode anzuzeigen |
lazy-loading-value-holder.md
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