@Ocramius @asgrim @RoaveTeam Imma start calling you Gandalphp.
— Lee Davis (@leedavis81) 9 July 2015An African / Caribbean / South US religion
Vodou means Spirit in west-african cultures
There are different variations of Vodou
Vodun is a fatalist creed
Events are pre-defined, in a chain of cause and effect
One must ask the lwa (spirits).
One does not act on his or her own.
I just got you interested in the talk
I don't want to talk about a religion that I do not know
PHP Magic!
In Programming, Magic is used to describe code that handles complex tasks, hiding that complexity to present a simple interface.
Thanks, Wikipedia!
Many Junior developers trying to over-abstract
Very few Senior developers, when building compromises
(just a refresh)
__construct __destruct __get __set __isset __unset __sleep __wakeup __clone __invoke __call __callStatic __set_state __debugInfo
ReflectionClass
ReflectionProperty
ReflectionMethod
ReflectionFunction
$f = function () {};
$f = (function () {})->bindTo($that, 'Foo');
(No, this syntax won't work, sadly)
func_get_args()
debug_backtrace()
isset
unset
(array) cast
Generally referred to as friend object
Our puppet:
class User { private $name; private $surname; public function __construct($name, $surname) { $this->name = $name; $this->surname = $surname; } public function sayHello() { return 'Hello, I\'m ' . $this->name . ' ' . $this->surname . '!' . PHP_EOL; } }
Simplistic puppeteer:
class Puppeteer { public $properties = []; public function __construct($puppet) { foreach ( (new ReflectionClass($puppet))->getProperties() as $property ) { Closure::bind(function (& $properties) use ($property) { $name = $property->getName(); $properties[$name] = & $this->$name; }, $puppet, $property->getDeclaringClass()->getName()) ->__invoke($this->properties); } } }
$user = new User('James', 'Titcumb'); var_dump($user->sayHello()); $puppeteer = new Puppeteer($user); $puppeteer->properties['name'] = 'A'; $puppeteer->properties['surname'] = 'Minion'; var_dump($user->sayHello());
A decent puppeteer example
class Foo { private $bar = '0'; private saySomething($baz) { return $this->bar . $baz; } }
$altrEgo = AltrEgo::create(new Foo()); $altrEgo->bar = '11'; var_dump($altrEgo->saySomething('22'));
class Thing { public $something = 'foo'; public function saySomething() { return $this->something; } }
$thing = new Thing(); var_dump($thing->saySomething()); unset($thing->something); var_dump($thing->saySomething()); // ???
class MagicThing { public $something = 'foo'; public function saySomething() { return $this->something; } public function __get($name) { throw new DomainException('Stop touching my things!'); } }
$thing = new Thing(); var_dump($thing->saySomething()); unset($thing->something); var_dump($thing->saySomething()); // ???
A programming paradigm to separate cross-cutting concerns
Usually considered magic
Not very different from macros
In PHP, usually rewrites files when they are included
AOP framework for PHP
No extensions required
class CatchAll implements \Go\Aop\Aspect { /** @Go\Lang\Annotation\Before("execution(*->*(*))") */ public function beforeAnything( \Go\Aop\Intercept\MethodInvocation $invocation ) { var_dump($invocation->getMethod()->getName()); return $invocation->proceed(); } }
$foo->bar(); $bar->baz();
class Foo { private $thisWillGoWrongSomewhere = 'OHAI!'; public function __debugInfo() { // let me confuse you a bit return []; } }
var_dump(new Foo());
var_dump((object) ["\0Foo\0bar" => 'baz']);
$foo = (object) ["\0Foo\0bar" => 'baz']; var_dump($foo->{"\0Foo\0bar"});
$foo = (object) ["\0Foo\0bar" => 'baz']; var_dump($foo->bar);
$foo = (object) ["\0Foo\0bar" => 'baz']; $rp = new ReflectionProperty('stdClass', 'bar'); $rp->setAccessible(true); var_dump($rp->getValue($foo));
$foo = (object) ["\0Foo\0bar" => 'baz']; var_dump(Closure::bind(function () { return $this->baz; }, $foo, 'Foo')->__invoke());
Instantiate classes without calling their constructor.
class NotInstantiableSingleton { public static function getInstance() { /* horror */ } private function __construct() {} }
$instance = new NotInstantiableSingleton(); // crash
$instance = (new \Doctrine\Instantiator\Instantiator()) ->instantiate('NotInstantiableSingleton');
Object internal initialization event system
class Foo { use Vent\VentTrait; private $bar; public function __construct() { $this->registerEvent('read', 'bar', function() { echo 'Reading "bar"' . PHP_EOL; }); } public function doSomething() { return $this->bar; } }
$foo = new Foo(); $foo->doSomething();
Super fast lazy-initialized registry
$map = new \LazyMap\CallbackLazyMap(function ($name) { return new \ReflectionClass($name); });
var_dump($map->ArrayObject); var_dump($map->ArrayIterator);
Inspects Closures to build custom expressions in various DSLs
$db ->table('customers') ->where(function ($row) { return $row['age'] <= 50; }) ->orderByAscending(function ($row) { return $row['firstName']; }) ->select(function ($row) { return [ 'fullName' => $row['firstName'] . ' ' . $row['lastName'] ]; }) ->asArray()
SELECT CONCAT(CONCAT(customers.firstName, ' '), customers.lastName) AS fullName FROM ( SELECT * FROM ( SELECT * FROM (SELECT * FROM customers) AS customers WHERE (customers.age <= 50) ) AS customers ORDER BY customers.firstName ASC LIMIT 50 OFFSET 0 ) AS customers
Save/load code
Save/load your bugs! (you're welcome!)
$serializer = new SuperClosure\Serializer(); $serialized = $serializer->serialize(function () { echo file_get_contents(__FILE__); }); $serializer->unserialize($serialized)->__invoke();
All sorts of crazy hacks around object state
Lazy objects, AOP, Decorators
class Foo { public function __construct() { sleep(5); } public function doFoo() { echo "Foo!"; } }
$factory = new LazyLoadingValueHolderFactory(); $proxy = $factory->createProxy( 'Foo', function (& $wrapped, $p, $m, $args, & $initializer) { $initializer = null; $wrapped = new Foo(); } ); var_dump($proxy);
class Foo { public function doFoo() { echo "Foo!"; } }
$factory = new AccessInterceptorScopeLocalizerFactory(); $proxy = $factory->createProxy( new Foo(), ['doFoo' => function ($proxy) { echo "pre\n"; }], ['doFoo' => function ($proxy) { echo "post\n"; }] ); $proxy->doFoo();
class Foo { private $bar = 'baz'; public function sayBar() { echo $this->bar; } }
$factory = new LazyLoadingGhostFactory(); $proxy = $factory->createProxy( 'Foo', function ($p, $m, $args, & $initializer, array $properties) { $initializer = null; $properties["\0Foo\0bar"] = 'HAHA!'; } ); $proxy->sayBar();
DEV-MASTER only!!!
(not really)
class Foo { /** * @var \stdClass[] */ public $bar = []; }
$foo = new Foo();
$foo->bar = [new \stdClass()];
$foo->bar = new \stdClass; // crash