<?php
error_reporting(E_ALL);
class DtoException extends Exception
{
}
abstract class Dto
{
private static $propertyNamesByClass = array();
private function __construct(array $propertiesKeyValues)
{
foreach($propertiesKeyValues as $propertyName=>$propertyValue)
if(Static::hasPropertyName($propertyName))
$this->set($propertyName,$propertyValue);
}
public function __call($method, array $arguments)
{
$getOrSet = substr($method, 0, 3);
if($getOrSet != 'get' && $getOrSet != 'set')
throw new DtoException('"'.get_class($this).'" has no method "'.$method.'"');
$propertyName = strtolower(substr($method, 3));
if(!Static::hasPropertyName($propertyName))
throw new DtoException('"'.get_class($this).'" has no property "'.$propertyName.'"');
$getOrSetMethod = array($this,$getOrSet);
array_unshift($arguments,$propertyName);
return call_user_func_array($getOrSetMethod, $arguments);
}
public function __get($propertyName)
{
if(!Static::hasPropertyName($propertyName))
throw new DtoException('"'.get_class($this).'" has no property "'.$propertyName.'"');
return $this->get($propertyName);
}
public function __set($propertyName, $propertyValue)
{
if(!Static::hasPropertyName($propertyName))
throw new DtoException('"'.get_class($this).'" has no property "'.$propertyName.'"');
return $this->set($propertyName, $propertyValue);
}
public static function createFromArray($propertiesKeyValues)
{
return new Static($propertiesKeyValues);
}
public function set($propertyName, $propertyValue)
{
$this->$propertyName = $propertyValue;
}
public function get($propertyName)
{
return $this->$propertyName;
}
public static function getPropertyNames()
{
$className = get_called_class();
if(isset(self::$propertyNamesByClass[$className]))
return self::$propertyNamesByClass[$className];
$reflected = new ReflectionClass($className);
$properties = $reflected->getProperties(
ReflectionProperty::IS_PUBLIC
);
$propertyNames = array();
foreach($properties as $property) {
$propertyNames[] = $property->getName();
}
self::$propertyNamesByClass[$className] = $propertyNames;
return $propertyNames;
}
public static function hasPropertyName($propertyName)
{
$propertyNames = Static::getPropertyNames();
return in_array($propertyName,$propertyNames);
}
public function asArray()
{
$values = array();
foreach (Static::getPropertyNames() as $propertyName) {
$values[$propertyName] = $this->get($propertyName);
}
return $values;
}
public function __sleep()
{
$propertyNames = self::getPropertyNames();
foreach ($propertyNames as $propertyName) {
$propertyValue = $this->get($propertyName);
$this->set($propertyName, $propertyValue);
}
return $propertyNames;
}
public function __wakeup()
{
$propertyNames = self::getPropertyNames();
return $propertyNames;
}
}
class Person extends Dto
{
public $name;
public $surname;
}
class Test
{
const PERSON_NAME = 'name';
const PERSON_SURNAME = 'surname';
public function testProvideDtoPropertyNames()
{
$propertyNames = Person::getPropertyNames();
$expectedProperties = array(
self::PERSON_NAME,
self::PERSON_SURNAME,
);
$this->assertEquals(
$expectedProperties,
$propertyNames
);
}
public function testProvidePropertyViaGeneralGetter()
{
$dto = Person::createFromArray(array(
self::PERSON_NAME => 'Simone',
));
$this->assertEquals(
'Simone',
$dto->getName()
);
}
public function testDTOAcceptOnlyItsOwnProperties()
{
$dto = Person::createFromArray(array(
self::PERSON_NAME => 'Simone',
'non existent property' => 'Simone',
));
$expectedProperties = array(
self::PERSON_NAME => 'Simone',
self::PERSON_SURNAME => null,
);
$this->assertEquals(
$expectedProperties,
$dto->asArray()
);
}
public function testSerializationKeepSameProperties()
{
$properties = array(
self::PERSON_NAME => 'Simone',
self::PERSON_SURNAME => null,
);
$dto = Person::createFromArray($properties);
$serialized = serialize($dto);
$unserialized = unserialize($serialized);
$this->assertEquals(
$dto->asArray(),
$unserialized->asArray()
);
$this->assertEquals(
$properties,
$unserialized->asArray()
);
}
public function assertEquals($a,$b)
{
$serializeA = serialize($a);
$serializeB = serialize($b);
echo ($serializeA==$serializeB?'Pass':'FAIL').' : '.$serializeA.' ; '.$serializeB."\n";
}
}
$test = new Test();
$test->testProvideDtoPropertyNames();
$test->testProvidePropertyViaGeneralGetter();
$test->testDTOAcceptOnlyItsOwnProperties();
$test->testSerializationKeepSameProperties();
preferences:
49.03 ms | 402 KiB | 5 Q