- ob_get_clean: documentation ( source)
- ob_start: documentation ( source)
- preg_match: documentation ( source)
- debug_zval_dump: documentation ( source)
<?php
// from http://stackoverflow.com/a/3764809/4251625
function refcount($var)
{
ob_start();
debug_zval_dump($var);
$dump = ob_get_clean();
$matches = array();
preg_match('/refcount\(([0-9]+)/', $dump, $matches);
$count = $matches[1];
//3 references are added, including when calling debug_zval_dump()
return $count - 3;
}
class SomethingBuilder
{
protected $value;
protected $listeners = [];
protected function dispatchEvent($evt){
foreach($this->listeners as $listener)
$listener($evt);
}
function addEventListener($listener){
$this->listeners[] = $listener;
}
function getValue(){
return $this->value;
}
function setValue($value){
$this->dispatchEvent('beforechange');
$this->value = $value;
}
function freeze(){
return new SomethingFinalBuilderWrapper($this);
}
}
class SomethingFinalBuilderWrapper
{
protected $builder;
function __construct(SomethingBuilder $builder){
$this->builder = $builder;
$this->builder->addEventListener(function($evt){
if($evt !== 'beforechange') return;
echo refcount($this->builder);
// if(refcount($this->builder) > 1)
$this->builder = clone $this->builder;
echo "clone happened\n";
});
}
function getValue(){
return $this->builder->getValue();
}
}
$x = new SomethingBuilder();
$x->setValue(10);
echo $x->getValue() . "\n";
$y = $x->freeze();
$x->setValue(20);
echo $y->getValue() . "\n";
echo $x->getValue() . "\n";
$y = $x->freeze();
$z = $x->freeze();
$x->setValue(20);
echo $y->getValue() . "\n";
echo $x->getValue() . "\n";