|
class Proxy extends Document |
|
{ |
|
/** @var ProxiedProperty[] */ |
|
private $properties; |
|
|
|
/** @var \Closure */ |
|
private $initializer; |
|
|
|
/** @var bool */ |
|
private $initialized = false; |
|
|
|
/** @var array */ |
|
private $internalProperties = ['properties', 'initialized', 'initializer', 'internalProperties']; |
|
|
|
public function __construct($initializer) |
|
{ |
|
$this->initializer = $initializer; |
|
|
|
$this->initializeProperties(); |
|
} |
|
|
|
public function initializePartialProperties($properties) |
|
{ |
|
foreach ($properties as $name => $value) { |
|
if (! isset($this->properties[$name])) { |
|
throw new \Exception('Not found'); |
|
} |
|
|
|
$this->properties[$name]->setValue($value); |
|
} |
|
} |
|
|
|
private function initialize() |
|
{ |
|
$initializer = $this->initializer; |
|
$this->initializer = null; |
|
$this->initialized = true; |
|
|
|
$initializer->__invoke($this); |
|
} |
|
|
|
private function initializeProperties() |
|
{ |
|
$reflectionClass = new \ReflectionClass(get_parent_class($this)); |
|
$privateProperties = []; |
|
|
|
foreach ($reflectionClass->getProperties() as $reflectionProperty) { |
|
$propertyName = $reflectionProperty->getName(); |
|
$this->properties[$propertyName] = new ProxiedProperty($this, $propertyName, $reflectionProperty); |
|
|
|
if ($reflectionProperty->isPrivate()) { |
|
$privateProperties[] = $propertyName; |
|
} else { |
|
unset($this->$propertyName); |
|
} |
|
} |
|
|
|
if ($privateProperties !== []) { |
|
$closure = function (Document $document) use ($privateProperties) { |
|
foreach ($privateProperties as $property) { |
|
unset($document->$property); |
|
} |
|
}; |
|
|
|
$unsetProperties = Closure::bind($closure, $this, get_parent_class($this)); |
|
$unsetProperties($this); |
|
} |
|
} |
|
|
|
public function __get($name) |
|
{ |
|
if (isset($this->properties[$name])) { |
|
if (! $this->initialized) { |
|
echo "__get({$name}): Initialize proxy\n"; |
|
$this->initializer && $this->initialize(); |
|
} |
|
|
|
return $this->properties[$name]->getValue(); |
|
} |
|
|
|
trigger_error(sprintf('Undefined property: %s::$%s', __CLASS__, $name), E_USER_NOTICE); |
|
} |
|
|
|
public function __isset($name) |
|
{ |
|
if (isset($this->properties[$name])) { |
|
if (! $this->initialized) { |
|
echo "__isset({$name}): Initialize proxy\n"; |
|
$this->initializer && $this->initialize(); |
|
} |
|
|
|
return isset($this->name); |
|
} |
|
|
|
return false; |
|
} |
|
|
|
public function __set($name, $value) |
|
{ |
|
if (isset($this->properties[$name])) { |
|
if (! $this->initialized) { |
|
echo "__set({$name}): Initialize proxy\n"; |
|
$this->initializer && $this->initialize(); |
|
} |
|
|
|
$this->properties[$name]->setValue($value); |
|
|
|
return; |
|
} elseif (in_array($name, $this->internalProperties)) { |
|
trigger_error(sprintf('Undefined property: %s::$%s', __CLASS__, $name), E_USER_NOTICE); |
|
} |
|
|
|
$this->$name = $value; |
|
} |
|
} |