3v4l.org

run code in 150+ php & hhvm versions
Bugs & Features
<?php class Book { protected $title; protected $author; protected $genres; public function __construct() { $this->genres = new ArrayObject(); } public function addGenre($genre) { $this->genres[] = $genre; return $this; } public function getGenres() { return $this->genres; } public function setAuthor(Person $author) { $this->author = $author; return $this; } public function getAuthor() { return $this->author; } public function setTitle($title) { $this->title = $title; return $this; } public function getTitle() { return $this->title; } } class Person { protected $firstName; protected $lastName; public function __construct($firstName = null, $lastName = null) { $this->setFirstName($firstName); $this->setLastName($lastName); } public function setFirstName($firstName) { $this->firstName = $firstName; return $this; } public function getFirstName() { return $this->firstName; } public function setLastName($lastName) { $this->lastName = $lastName; return $this; } public function getLastName() { return $this->lastName; } } interface Hydrator { public function hydrate($object, array $data); public function extract($object); } class ReflectionHydrator implements Hydrator { public function hydrate($object, array $data) { $reflection = new ReflectionClass($object); $transform = function ($key) { return 'set' . str_replace(' ', '', ucwords(str_replace('_', ' ', $key))); }; foreach ($reflection->getMethod() as $method) { if (!$method->isPublic() || 0 !== strpos($method->getName(), 'set')) { continue; } $field = lcfirst(substr($method->getName(), 3)); // @todo } } public function extract($object) { $data = array(); $reflection = new ReflectionClass($object); $transform = function ($key) { return '_' . strtolower(array_shift($key)); }; foreach ($reflection->getMethods() as $method) { if (!$method->isPublic() || 0 !== strpos($method->getName(), 'get')) { continue; } $field = lcfirst(substr($method->getName(), 3)); $normalized = preg_replace_callback('/([A-Z])/', $transform, $field); $data[$normalized] = $method->invoke($object); } return $data; } } class DryReflectionHydrator implements Hydrator { public function extract($object) { $transform = function ($key) { return '_' . strtolower(array_shift($key)); }; $data = array(); // Process get methods $this->processMethods($object, 'get', function ($field, ReflectionMethod $method) use (&$data, $transform) { $normalized = preg_replace_callback('/([A-Z])/', $transform, $field); $data[$normalized] = $method->invoke(null); }); return $data; } public function hydrate($object, array $data) { $transform = function ($key) { return 'set' . str_replace(' ', '', ucwords(str_replace('_', ' ', $key))); }; $this->processMethods($object, 'set', function($field, ReflectionMethod $method) use ($data, $transform) { $method->invoke(null, $data[$transform($field)]); }); } protected function processMethods($object, $prefix, $callback) { $reflection = new ReflectionClass($object); foreach ($reflection->getMethods() as $method) { if (!$method->isPublic() || 0 !== strpos($method->getName(), $prefix)) { continue; } $field = lcfirst(substr($method->getName(), strlen($prefix))); $callback($field, $method); } } } $book = new Book(); $book->setTitle('Harry potter'); $book->addGenre('Drama')->addGenre('Nosense'); $book->setAuthor(new Person('James', 'Bond')); $hydrator = new ReflectionHydrator(); var_dump($hydrator->extract($book)); var_dump($hydrator->extract($book->getAuthor())); $dryHydrator = new DryReflectionHydrator(); var_dump($dryHydrator->extract($book)); var_dump($dryHydrator->extract($book->getAuthor()));
Output for 7.1.0
array(3) { ["genres"]=> object(ArrayObject)#2 (1) { ["storage":"ArrayObject":private]=> array(2) { [0]=> string(5) "Drama" [1]=> string(7) "Nosense" } } ["author"]=> object(Person)#3 (2) { ["firstName":protected]=> string(5) "James" ["lastName":protected]=> string(4) "Bond" } ["title"]=> string(12) "Harry potter" } array(2) { ["first_name"]=> string(5) "James" ["last_name"]=> string(4) "Bond" } Fatal error: Uncaught ReflectionException: Trying to invoke non static method Book::getGenres() without an object in /in/7Zour:141 Stack trace: #0 /in/7Zour(141): ReflectionMethod->invoke(NULL) #1 /in/7Zour(166): DryReflectionHydrator->{closure}('genres', Object(ReflectionMethod)) #2 /in/7Zour(142): DryReflectionHydrator->processMethods(Object(Book), 'get', Object(Closure)) #3 /in/7Zour(185): DryReflectionHydrator->extract(Object(Book)) #4 {main} thrown in /in/7Zour on line 141
Process exited with code 255.
Output for 7.0.0 - 7.0.14
array(3) { ["genres"]=> object(ArrayObject)#2 (1) { ["storage":"ArrayObject":private]=> array(2) { [0]=> string(5) "Drama" [1]=> string(7) "Nosense" } } ["author"]=> object(Person)#3 (2) { ["firstName":protected]=> string(5) "James" ["lastName":protected]=> string(4) "Bond" } ["title"]=> string(12) "Harry potter" } array(2) { ["first_name"]=> string(5) "James" ["last_name"]=> string(4) "Bond" } Fatal error: Uncaught ReflectionException: Non-object passed to Invoke() in /in/7Zour:141 Stack trace: #0 /in/7Zour(141): ReflectionMethod->invoke(NULL) #1 /in/7Zour(166): DryReflectionHydrator->{closure}('genres', Object(ReflectionMethod)) #2 /in/7Zour(142): DryReflectionHydrator->processMethods(Object(Book), 'get', Object(Closure)) #3 /in/7Zour(185): DryReflectionHydrator->extract(Object(Book)) #4 {main} thrown in /in/7Zour on line 141
Process exited with code 255.
Output for hhvm-3.10.0 - 3.12.0
array(3) { ["genres"]=> object(ArrayObject)#2 (1) { ["storage":"ArrayObject":private]=> array(2) { [0]=> string(5) "Drama" [1]=> string(7) "Nosense" } } ["author"]=> object(Person)#3 (2) { ["firstName":protected]=> string(5) "James" ["lastName":protected]=> string(4) "Bond" } ["title"]=> string(12) "Harry potter" } array(2) { ["first_name"]=> string(5) "James" ["last_name"]=> string(4) "Bond" } Fatal error: Unknown method Book::getGenres in /in/7Zour on line 141
Process exited with code 255.
Output for 5.4.0 - 5.6.28
array(3) { ["genres"]=> object(ArrayObject)#2 (1) { ["storage":"ArrayObject":private]=> array(2) { [0]=> string(5) "Drama" [1]=> string(7) "Nosense" } } ["author"]=> object(Person)#3 (2) { ["firstName":protected]=> string(5) "James" ["lastName":protected]=> string(4) "Bond" } ["title"]=> string(12) "Harry potter" } array(2) { ["first_name"]=> string(5) "James" ["last_name"]=> string(4) "Bond" } Fatal error: Uncaught exception 'ReflectionException' with message 'Non-object passed to Invoke()' in /in/7Zour:141 Stack trace: #0 /in/7Zour(141): ReflectionMethod->invoke(NULL) #1 /in/7Zour(166): DryReflectionHydrator->{closure}('genres', Object(ReflectionMethod)) #2 /in/7Zour(142): DryReflectionHydrator->processMethods(Object(Book), 'get', Object(Closure)) #3 /in/7Zour(185): DryReflectionHydrator->extract(Object(Book)) #4 {main} thrown in /in/7Zour on line 141
Process exited with code 255.
Output for 5.3.0 - 5.3.29
array(3) { ["genres"]=> object(ArrayObject)#2 (1) { ["storage":"ArrayObject":private]=> array(2) { [0]=> string(5) "Drama" [1]=> string(7) "Nosense" } } ["author"]=> object(Person)#3 (2) { ["firstName":protected]=> string(5) "James" ["lastName":protected]=> string(4) "Bond" } ["title"]=> string(12) "Harry potter" } array(2) { ["first_name"]=> string(5) "James" ["last_name"]=> string(4) "Bond" } Fatal error: Uncaught exception 'ReflectionException' with message 'Non-object passed to Invoke()' in /in/7Zour:141 Stack trace: #0 /in/7Zour(141): ReflectionMethod->invoke(NULL) #1 /in/7Zour(166): {closure}('genres', Object(ReflectionMethod)) #2 /in/7Zour(142): DryReflectionHydrator->processMethods(Object(Book), 'get', Object(Closure)) #3 /in/7Zour(185): DryReflectionHydrator->extract(Object(Book)) #4 {main} thrown in /in/7Zour on line 141
Process exited with code 255.