Skip to content

Commit ac4394c

Browse files
committed
Updated README with more content
1 parent ebc033b commit ac4394c

File tree

3 files changed

+72
-20
lines changed

3 files changed

+72
-20
lines changed

README.md

+68-19
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,13 @@ A PHP Library for serializing closures and anonymous functions.
1313

1414
Once upon a time, I tried to serialize a PHP `Closure` object. As you can
1515
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:
1717

1818
> Uncaught exception 'Exception' with message 'Serialization of 'Closure' is
1919
> not allowed'
2020
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:
2323

2424
```php
2525
use SuperClosure\Serializer;
@@ -141,6 +141,24 @@ should choose the fastest analyzer that supports the features you need.
141141
</tbody>
142142
</table>
143143

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+
144162
You can choose the analyzer you want to use when you instantiate the
145163
`Serializer`. If you do not specify one, the `AstAnalyzer` is used by default,
146164
since it has the most capabilities.
@@ -159,22 +177,53 @@ $serializer = new Serializer(new AstAnalyzer());
159177
$serializer = new Serializer(new TokenAnalyzer());
160178
```
161179

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`:
163183

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+
```
178227

179228
## Installation
180229

@@ -201,7 +250,7 @@ about the 7:50 mark they show how you can push a closure onto a queue as a job
201250
so that it can be executed by a worker. This is nice because you do not have to
202251
create a whole class for a job that might be really simple.
203252

204-
## Tell me more about how this came about
253+
## Tell me about how this project started
205254

206255
It all started back in the beginning of 2010 when PHP 5.3 was starting to
207256
gain traction. I set out to prove that serializing a closure could be done,

src/Serializer.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ public function getData(\Closure $closure, $forSerialization = false)
102102
/**
103103
* Recursively traverses and wraps all Closure objects within the value.
104104
*
105-
* NOTE: THIS METHOD MAY NOT WORK IN ALL SITUATIONS, SO BE CAREFUL.
105+
* NOTE: THIS MAY NOT WORK IN ALL USE CASES, SO USE AT YOUR OWN RISK.
106106
*
107107
* @param mixed $data Any variable that contains closures.
108108
* @param SerializerInterface $serializer The serializer to use.

src/SerializerInterface.php

+3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
<?php namespace SuperClosure;
22

3+
use SuperClosure\Exception\ClosureUnserializationException;
4+
35
/**
46
* Interface for a serializer that is used to serialize Closure objects.
57
*/
@@ -21,6 +23,7 @@ public function serialize(\Closure $closure);
2123
*
2224
* @param string $serialized Serialized closure.
2325
*
26+
* @throws ClosureUnserializationException if unserialization fails.
2427
* @return \Closure Unserialized closure.
2528
*/
2629
public function unserialize($serialized);

0 commit comments

Comments
 (0)