Tuesday, September 06, 2011

Automatically assign constructor parameters to private properties

In Scala, a JVM language, constructor parameters become private fields of the class, by default:
class Person(age:Int) {
  def grow() = {
    age += 1
  }
}
I find it handy, as I always use private properties which are the target of dependency injection, in particular constructor injection.
Here's how to emulate this functionality in PHP, with great hacks. I post this code here so it won't be lost in the interwebs.
<?php
class AutomatedAssignmentOfConstructorParametersTest extends PHPUnit_Framework_TestCase
{
public function testParametersAreAssignedBasingOnTheirNames()
{
$object = new MyClass(1, 2);
$this->assertEquals(1, $object->getFirst());
$this->assertEquals(2, $object->getSecond());
}
}
class MyClass
{
private $first;
private $second;
public function __construct($first, $second)
{
assignConstructorParameters($this, get_defined_vars());
}
public function getFirst()
{
return $this->first;
}
public function getSecond()
{
return $this->second;
}
}
function assignConstructorParameters($object, $constructorParameters)
{
$class = get_class($object);
foreach ($constructorParameters as $name => $value) {
if ($name == 'this') {
continue;
}
$reflectionProperty = new ReflectionProperty($class, $name);
$reflectionProperty->setAccessible(true);
$reflectionProperty->setValue($object, $value);
$reflectionProperty->setAccessible(false);
}
}
view raw gistfile1.aw hosted with ❤ by GitHub

7 comments:

Ocramius Aethril said...

The idea is quite nice, but I'd prefer to see that function placed as a static method, thus usable with inheritance and with the new coming threats :D

Marijn said...

As much as I like this if it were a language construct, implementing it like this feels too hackish for me... Than again, I prefer explicit over magic. Perhaps it's just my taste...

Anonymous said...

I doubt that all casual readers will understand why this is necessary in some cases - why it isn't always possible to simply set $this->first in the constructor. It would be helpful to many if you posted a brief explanation - the example you posted could simply set $this->first from the constructor, so it doesn't demonstrate when/why you would need this.

Dominik said...

I also find that a bit too hackish. I mean it saves you a bit of code you'd need to write but I would rather write it than introduce this magic, which might not be clear to everyone reading my code.

Although I always try to not use Reflection as that can get very costly when instanciating a lot of objects that way.

But having that as a language construct would be very cool like it's in Scala :)

Giorgio said...

It's not intended for real world usage, and never *required*.
I had to use reflection because when outsourcing the code from the constructor, private fields become not visible. I would prefer it as a language feature like Marijn and Dominik said.
The only usage for this code is quick experimentation (call it pretotyping): not having to patch the PHP core to see if the feature comes handy or it's horrible.

markus said...

For simple DTO's I use this approach:

class MyDto extends ArrayObject
{

public function __construct($id, $name)
{
parent::__construct(compact('id', 'name'));
}

}

This has some benefits and is simple. But of course the properties are public. Its just a tradeoff...

Giorgio said...

I too use ArrayObject as a low-cost DTO, there's usually no problem with public properties on them.

Featured post

A map metaphor for architectural diagrams

It is a (two-dimension) representation of a pipe. The map is not the territory , but in software engineering terms they are models of it....

Popular posts