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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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); | |
} | |
} |
7 comments:
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
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...
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.
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 :)
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.
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...
I too use ArrayObject as a low-cost DTO, there's usually no problem with public properties on them.
Post a Comment