mirror, mirror on the wall (phpem unconf 2015)

46
Mirror, Mirror on the Wall James Titcumb PHPem Unconference 2015

Upload: james-titcumb

Post on 26-Jan-2017

366 views

Category:

Technology


2 download

TRANSCRIPT

Page 1: Mirror, mirror on the wall (PHPem Unconf 2015)

Mirror, Mirror on the WallJames Titcumb

PHPem Unconference 2015

Page 3: Mirror, mirror on the wall (PHPem Unconf 2015)

Reflection

Page 4: Mirror, mirror on the wall (PHPem Unconf 2015)
Page 5: Mirror, mirror on the wall (PHPem Unconf 2015)

© 1937 Disney’s Snow White - disneyscreencaps.com

Page 6: Mirror, mirror on the wall (PHPem Unconf 2015)
Page 7: Mirror, mirror on the wall (PHPem Unconf 2015)

● Structure● Metadata● Values● Type introspection● Modification

Reflection

Page 8: Mirror, mirror on the wall (PHPem Unconf 2015)

How does it work?

Page 9: Mirror, mirror on the wall (PHPem Unconf 2015)

GET_REFLECTION_OBJECT_PTR(ce);

lc_name = zend_str_tolower_dup(name, name_len);

if ((ce == zend_ce_closure && (name_len == sizeof(ZEND_INVOKE_FUNC_NAME)-1)

&& memcmp(lc_name, ZEND_INVOKE_FUNC_NAME, sizeof(ZEND_INVOKE_FUNC_NAME)-1) == 0)

|| zend_hash_str_exists(&ce->function_table, lc_name, name_len)) {

efree(lc_name);

RETURN_TRUE;

} else {

efree(lc_name);

RETURN_FALSE;

}

Page 10: Mirror, mirror on the wall (PHPem Unconf 2015)

Okay. What now?

Page 11: Mirror, mirror on the wall (PHPem Unconf 2015)

github.com/ /BetterReflection

Better Reflection!

Page 12: Mirror, mirror on the wall (PHPem Unconf 2015)
Page 13: Mirror, mirror on the wall (PHPem Unconf 2015)

What?

Page 14: Mirror, mirror on the wall (PHPem Unconf 2015)

Why?

Page 15: Mirror, mirror on the wall (PHPem Unconf 2015)

How?

Page 16: Mirror, mirror on the wall (PHPem Unconf 2015)

Magic of the AST

Page 17: Mirror, mirror on the wall (PHPem Unconf 2015)

source: http://goo.gl/HORwLQ

Page 18: Mirror, mirror on the wall (PHPem Unconf 2015)

WTF is AST?

Page 19: Mirror, mirror on the wall (PHPem Unconf 2015)

use PhpParser\ParserFactory;

$parser = (new ParserFactory)

->create(ParserFactory::PREFER_PHP7);

print_r($parser->parse(

file_get_contents('ast-demo-src.php')

));

Page 20: Mirror, mirror on the wall (PHPem Unconf 2015)

<?php

echo "Hello world";

Page 21: Mirror, mirror on the wall (PHPem Unconf 2015)

AST

`-- Echo statement

`-- String, value "Hello world"

Page 22: Mirror, mirror on the wall (PHPem Unconf 2015)

<?php

echo "Hello " . "world";

Page 23: Mirror, mirror on the wall (PHPem Unconf 2015)

AST

`-- Echo statement

`-- Concat

|-- Left

| `-- String, value "Hello "

`-- Right

`-- String, value "world"

Page 24: Mirror, mirror on the wall (PHPem Unconf 2015)

AST to Reflection

Page 25: Mirror, mirror on the wall (PHPem Unconf 2015)

Benefits?

Page 26: Mirror, mirror on the wall (PHPem Unconf 2015)

ReflectionProperty->getDocBlockTypes()

Types!

Page 27: Mirror, mirror on the wall (PHPem Unconf 2015)

Using Better Reflection

Page 28: Mirror, mirror on the wall (PHPem Unconf 2015)

$reflection = new ReflectionClass(

'BetterReflectionTest\Fixture\ExampleClass'

);

$this->assertSame(

'ExampleClass',

$reflection->getShortName()

);

Page 29: Mirror, mirror on the wall (PHPem Unconf 2015)

$reflection = ReflectionClass::createFromName(

'BetterReflectionTest\Fixture\ExampleClass'

);

$this->assertSame(

'ExampleClass',

$reflection->getShortName()

);

Page 30: Mirror, mirror on the wall (PHPem Unconf 2015)

// In ReflectionClass :

public static function createFromName($className)

{

return ClassReflector::buildDefaultReflector()->reflect($className);

}

// In ClassReflector :

public static function buildDefaultReflector()

{

return new self(new AggregateSourceLocator([

new PhpInternalSourceLocator(),

new EvaledCodeSourceLocator(),

new AutoloadSourceLocator(),

]));

}

Page 31: Mirror, mirror on the wall (PHPem Unconf 2015)

(don’t try this at home kids!)

Some voodoo...

Page 32: Mirror, mirror on the wall (PHPem Unconf 2015)
Page 33: Mirror, mirror on the wall (PHPem Unconf 2015)

class MyClass

{

public function foo()

{

return 5;

}

}

Page 34: Mirror, mirror on the wall (PHPem Unconf 2015)

// Create the reflection first

// ***BEFORE*** class is loaded

$classInfo = ReflectionClass::createFromName('MyClass');

Page 35: Mirror, mirror on the wall (PHPem Unconf 2015)

// Override the body...!

$methodInfo = $classInfo->getMethod('foo');

$methodInfo->setBody(function () {

return 4;

});

Page 36: Mirror, mirror on the wall (PHPem Unconf 2015)

// Save the class and require it

$classCode = (new CodePrinter())->prettyPrint([$classInfo->getAst()]);

$tmpFile = tempnam(sys_get_temp_dir(), 'br-monkey-patching');

file_put_contents($tmpFile, '<?php ' . $classCode);

require_once($tmpFile);

unlink($tmpFile);

Page 37: Mirror, mirror on the wall (PHPem Unconf 2015)

// Now create an instance, and call the function...

$c = new MyClass();

var_dump($c->foo()); // will be 4!!!

Page 38: Mirror, mirror on the wall (PHPem Unconf 2015)
Page 39: Mirror, mirror on the wall (PHPem Unconf 2015)

What’s in it for me?

Page 40: Mirror, mirror on the wall (PHPem Unconf 2015)

The future...

Page 41: Mirror, mirror on the wall (PHPem Unconf 2015)

● DONE Currently: rewriting the internals○ SourceLocators “might” return some code ?!

● DONE Returning AST/Code for method/fn

Ideas/plans - DONE

Page 42: Mirror, mirror on the wall (PHPem Unconf 2015)

● WIP More compatibility core reflection● WIP Reflect core fns with default params

○ This is not currently possible with core reflection● WIP Modification & exporting● WIP Reflecting on closures

Ideas/plans - WIP

Page 43: Mirror, mirror on the wall (PHPem Unconf 2015)

● Adding a getColumn() function● PHP 7 compatibility● @inheritDoc traversal (to inherit type hints)● Make it faster

Ideas/plans

Page 44: Mirror, mirror on the wall (PHPem Unconf 2015)

¯\_(ツ)_/¯

Page 45: Mirror, mirror on the wall (PHPem Unconf 2015)

github.com/ /BetterReflection

Better Reflection

Page 46: Mirror, mirror on the wall (PHPem Unconf 2015)

Any questions? :)

https://joind.in/15485James Titcumb @asgrim