<?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, $object, ReflectionMethod $method) use (&$data, $transform) {
$normalized = preg_replace_callback('/([A-Z])/', $transform, $field);
$data[$normalized] = $method->invoke($object);
});
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, $object, ReflectionMethod $method) use ($data, $transform) {
$method->invoke($object, $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, $object, $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 5.3.0 - 5.3.29, 5.4.0 - 5.4.45, 5.5.0 - 5.5.38, 5.6.0 - 5.6.28, 7.0.0 - 7.0.20, 7.1.0 - 7.1.10, 7.2.0 - 7.2.33, 7.3.12 - 7.3.33, 7.4.0 - 7.4.33, 8.0.0 - 8.0.30, 8.1.0 - 8.1.28, 8.2.0 - 8.2.18, 8.3.0 - 8.3.6
- 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"
}
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"
}
preferences:
242.81 ms | 406 KiB | 301 Q