Skip to content

Instantly share code, notes, and snippets.

@Ocramius
Last active March 12, 2021 14:14
Show Gist options
  • Save Ocramius/5365052 to your computer and use it in GitHub Desktop.
Save Ocramius/5365052 to your computer and use it in GitHub Desktop.
Self hydrating object proxy in PHP Provides faster hydration by removing the need for reflection.

This piece of code tries to reduce the performance overhead needed to populate an object's properties via reflection.

An example of its usage can be found at http://3v4l.org/he2dF

<?php
class Foo
{
protected $foo;
protected $bar;
protected $baz;
}
<?php
class FooSelfHydratingProxy extends Foo implements HydratorInterface
{
/** zero-argument constructor since this is just a helper class for hydration */
public function __construct()
{
}
/**
* the `Foo` typehint is not part of the interface - here only for the sake of readability/clearness
*/
public function hydrate($data, Foo $object)
{
$object->foo = $data['foo'];
$object->bar = $data['bar'];
$object->baz = $data['baz'];
}
/**
* the `Foo` typehint is not part of the interface - here only for the sake of readability/clearness
*/
public function extract(Foo $object)
{
return array('foo' => $object->foo, 'bar' => $object->bar, 'baz' => $object->baz);
}
}
<?php
$iterations = 100000;
class A {protected $a; protected $b; protected $c;}
class AHydrator extends A {
public function hydrate(A $a, array $data)
{
$a->a = $data['a'];
$a->b = $data['b'];
$a->c = $data['c'];
}
}
$data = array('a' => 1, 'b' => 2, 'c' => 3);
$a = new A();
$h = new AHydrator();
for ($i = 0; $i < $iterations; $i++) {
$h->hydrate($a, $data);
}
<?php
$iterations = 100000;
class A {protected $a; protected $b; protected $c;}
$rA = new ReflectionProperty('A', 'a');
$rB = new ReflectionProperty('A', 'b');
$rC = new ReflectionProperty('A', 'c');
$rA->setAccessible(true);
$rB->setAccessible(true);
$rC->setAccessible(true);
$data = array('a' => 1, 'b' => 2, 'c' => 3);
$a = new A();
for ($i = 0; $i < $iterations; $i++) {
$rA->setValue($a, $data['a']);
$rB->setValue($a, $data['b']);
$rC->setValue($a, $data['c']);
}
@prograhammer
Copy link

This is brilliant @Ocramius! I was looking for a way to hydrate my entities without using slow Reflection or adding setters unnecessarily.

@Ocramius
Copy link
Author

Ocramius commented Aug 1, 2015

@prograhammer this is just meant for D2 internals, not for the "general public"

@aderuwe
Copy link

aderuwe commented Aug 25, 2015

@Ocramius it's a valid strategy perhaps though, for projects that can't use the D2 ORM ...

@ChubV
Copy link

ChubV commented Jan 13, 2016

@Ocramius so if this change will happen in D2 all entities should be refactored to have protected properties instead of private? Also extending entity can have some drawbacks... Please, look at this example . It also has nice performance and can be used to set private properties.

@flowl
Copy link

flowl commented Feb 18, 2020

Why does HydratorA extend A? It's confusing without doing anything. Also the questino is not answered: Why was the reflection there in the first place? Probably because of unknown properties..

@Ocramius
Copy link
Author

@flowl that's an old concept that I used in a library called GeneratedHydrator: https://github.com/Ocramius/GeneratedHydrator

The idea is that by using inheritance, you can avoid property access hooks that are used by PHP to determine whether you can access a field or not.

@flowl
Copy link

flowl commented Feb 18, 2020

The idea is that by using inheritance, you can avoid property access hooks that are used by PHP to determine whether you can access a field or not.

Ahh you are right, I remember... extending a class gives the current one permission to access non-public properties.
I just downloaded GeneratedHydrator to try it out :-)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment