@@ -13,13 +13,13 @@ A PHP Library for serializing closures and anonymous functions.
13
13
14
14
Once upon a time, I tried to serialize a PHP ` Closure ` object. As you can
15
15
probably guess, it doesn't work at all. In fact, you get a very specific error
16
- message from your friendly, neighborhood PHP Runtime:
16
+ message from the PHP Runtime:
17
17
18
18
> Uncaught exception 'Exception' with message 'Serialization of 'Closure' is
19
19
> not allowed'
20
20
21
- However, even though it is not " allowed" by PHP, the SuperClosure library makes
22
- it ** possible** to circumvent this limitation . Here's the way you use it:
21
+ Even though serializing closures is " not allowed" by PHP, the SuperClosure
22
+ library makes it ** possible** . Here's the way you use it:
23
23
24
24
``` php
25
25
use SuperClosure\Serializer;
@@ -141,6 +141,24 @@ should choose the fastest analyzer that supports the features you need.
141
141
</tbody >
142
142
</table >
143
143
144
+ ### Caveats
145
+
146
+ 1 . For any variables used by reference (e.g., `function () use (&$vars, &$like,
147
+ &$these) {…}`), the references are not maintained after serialization. The
148
+ only exception to this is recursive closure references.
149
+ 2 . If you have two closures defined on a single line (you shouldn't do this
150
+ anyway), you will not be able to serialize either one since it is ambiguous
151
+ which closure's code should be parsed (they are anonymous functions after
152
+ all).
153
+ 3 . ** Warning** : The ` eval() ` function is required to unserialize the closure.
154
+ This functions is considered dangerous by many, so you will have to evaluate
155
+ what precautions you may need to take when using this library. You should only
156
+ unserialize closures retrieved from a trusted source, otherwise you are
157
+ opening yourself up to code injection attacks. It is a good idea to encrypt
158
+ or sign serialized closures if you plan on storing or transporting them.
159
+
160
+ ### Analyzers
161
+
144
162
You can choose the analyzer you want to use when you instantiate the
145
163
` Serializer ` . If you do not specify one, the ` AstAnalyzer ` is used by default,
146
164
since it has the most capabilities.
@@ -159,22 +177,53 @@ $serializer = new Serializer(new AstAnalyzer());
159
177
$serializer = new Serializer(new TokenAnalyzer());
160
178
```
161
179
162
- ### Caveats
180
+ Analyzers are also useful on their own if you are just looking to do some
181
+ introspection on a Closure object. Check out what is returned when using the
182
+ ` AstAnalyzer ` :
163
183
164
- 1 . For any variables used by reference (e.g., `function () use (&$vars, &$like,
165
- &$these) {…}`), the references are not maintained after serialization. The
166
- only exception to this is recursive closure references.
167
- 2 . If you have two closures defined on a single line (you shouldn't do this
168
- anyway), you will not be able to serialize either one since it is ambiguous
169
- which closure's code should be parsed (they are anonymous functions after
170
- all).
171
- 3 . ** Warning** : The ` eval() ` function is required to unserialize the closure.
172
- This functions is considered dangerous by many, so you will have to evaluate
173
- what precautions you may need to take when using this library. Unfortunately,
174
- ` eval() ` * must* be used to make this library work. You should only
175
- unserialize closures retrieved from a trusted source, otherwise you are
176
- opening yourself up to code injection attacks. It may be a good idea to
177
- encrypt serialized closures if you plan on storing or transporting them.
184
+ ``` php
185
+ use SuperClosure\Analyzer\AstAnalyzer;
186
+
187
+ class Calculator
188
+ {
189
+ public function getAdder($operand)
190
+ {
191
+ return function ($number) use ($operand) {
192
+ return $number + $operand;
193
+ };
194
+ }
195
+ }
196
+
197
+ $closure = (new Calculator)->getAdder(5);
198
+ $analyzer = new AstAnalyzer();
199
+
200
+ var_dump($analyzer->analyze($closure));
201
+ // array(10) {
202
+ // 'reflection' => class ReflectionFunction#5 (1) {...}
203
+ // 'code' => string(68) "function ($number) use($operand) {
204
+ // return $number + $operand;
205
+ // };"
206
+ // 'hasThis' => bool(false)
207
+ // 'context' => array(1) {
208
+ // 'operand' => int(5)
209
+ // }
210
+ // 'hasRefs' => bool(false)
211
+ // 'binding' => class Calculator#2 (0) {...}
212
+ // 'scope' => string(10) "Calculator"
213
+ // 'isStatic' => bool(false)
214
+ // 'ast' => class PhpParser\Node\Expr\Closure#13 (2) {...}
215
+ // 'location' => array(8) {
216
+ // 'class' => string(11) "\Calculator"
217
+ // 'directory' => string(47) "/Users/lindblom/Projects/{...}/SuperClosureTest"
218
+ // 'file' => string(58) "/Users/lindblom/Projects/{...}/SuperClosureTest/simple.php"
219
+ // 'function' => string(9) "{closure}"
220
+ // 'line' => int(11)
221
+ // 'method' => string(22) "\Calculator::{closure}"
222
+ // 'namespace' => NULL
223
+ // 'trait' => NULL
224
+ // }
225
+ // }
226
+ ```
178
227
179
228
## Installation
180
229
@@ -201,7 +250,7 @@ about the 7:50 mark they show how you can push a closure onto a queue as a job
201
250
so that it can be executed by a worker. This is nice because you do not have to
202
251
create a whole class for a job that might be really simple.
203
252
204
- ## Tell me more about how this came about
253
+ ## Tell me about how this project started
205
254
206
255
It all started back in the beginning of 2010 when PHP 5.3 was starting to
207
256
gain traction. I set out to prove that serializing a closure could be done,
0 commit comments