/**
* test shallowCopy vs deepCopy
*
* shallowCopy:
* \code
* <Test>
* - array with closure
* - property with object <closure>
* - property with object <Alice>
* - array with object <closure>
* - property with object <closure>
* - property with object <Bob>
* - private var
* - public var
* - static object <DefaultObject>
* - protected var
* \endcode
*
* Actions of shallowCopy:
* - create new Test2
* - copy values from <Test>
* - don't touch statics
* - property with object (not closure): copy reference, not the object
* - property with object closure: rebind closure to <Test2>
* - property array with objects of type closure: recursively search closures and rebind them to <Test2>
*
* deepCopy:
* \code
* <Test>
* - array with closure
* - property with object <closure>
* - property with object <Alice>
* - array with object <closure>
* - property with object <closure>
* - property with object <Bob>
* - private var
* - public var
* - static object <DefaultObject>
* - protected var
* \endcode
*
* Actions of deepCopy:
* - create new Test2
* - copy values from <Test>
* - don't touch statics
* - property with object (not closure): object<IDefaultObject>->deepCopy, clone other objects
* - property with object closure: rebind closure to <Test2>
* - property array with objects (not closure): object<IDefaultObject>->deepCopy, clone other objects
* - property array with objects of type closure: recursively search closures and rebind them to <Test2>
*
* \todo How to handle closures in traversable objects?
*/
class test extends DefaultObject
{
private $name = 'base.name.notSet'; // name in multiple subjects are identical when closures are in old context
public $aV = 'base.av.notSet'; // av: arrayValue
public $sV = 'base.sv.notSet'; // sv: selfValue
private $private = 0;
static $static = 0;
protected $alice = NULL; // object as property
protected $fnA = []; // closure in array
protected $fnC = NULL; // closure as property
function __construct($name, Alice $alice, $private, DefaultObject $static)
{
$this->name = $name;
$this->alice = $alice;
$this->private = $private;
self::$static = $static;
$this->fnA['test']['self'] = function(){ return $this->aV; };
$this->fnC = function(){ return $this->sV; };
$this->set('init'.$name);
}
function __debugInfo()
{
return
[
'name' => $this->name,
//'aV' => $this->aV,
//'sV' => $this->sV,
'private' => $this->private,
'alice' => $this->alice,
'static' => self::$static,
'arrayClosure' => $this->fnA['test']['self'],
'propClosure' => $this->fnC,
];
}
function setClassName($n)
{
$this->name = $n;
}
function setAV($self, $alice)
{
$this->aV = 'base.av.'.$self;
$this->alice->aV = 'alic.av.'.$alice;
}
function setSV($self, $alice)
{
$this->sV = 'base.sv.'.$self;
$this->alice->sV = 'alic.sv.'.$alice;
}
function set($n)
{
$this->setAV('arrayClosure.'.$this->name.'.'.$n, 'arrayClosure.'.$this->name.'.'.$n);
$this->setSV('propertyClosure.'.$this->name.'.'.$n, 'propertyClosure.'.$this->name.'.'.$n);
}
function closureInArray()
{
$fn = $this->fnA['test']['self'];
echo 'closure in array: '.$fn().PHP_EOL
.' '.$this->alice->aT();
}
function closureAsProperty()
{
$fn = $this->fnC;
echo 'closure as property:'.$fn().PHP_EOL
.' '.$this->alice->sT();
}
function testClosureScope()
{
$this->closureInArray();
$this->closureAsProperty();
}
function compare(test $__Test)
{
$r = [];
$r['Test'] = $this === $__Test;
$r['Test->fnA'] = $this->fnA === $__Test->fnA;
$r['Test->fnC'] = $this->fnC === $__Test->fnC;
$r['Test->alice'] = $this->alice->compare($__Test->alice);
$r['Test::static'] = self::$static === $__Test::$static;
return ["Compare {$this->name} with {$__Test->name}" => $r];
}
}
class bob
{
}
class alice extends DefaultObject
{
public $aV = 'alice.av.notSet';
public $sV = 'alice.sv.notSet';
protected $fnA = [];
protected $fnC = NULL;
protected $__bob;
function __construct()
{
$this->fnA['test']['alice'] = function(){ return $this->aV;};
$this->fnC = function(){ return $this->sV; };
$this->__bob = new bob;
}
function __debugInfo()
{
return
[
//'aV' => $this->aV,
//'sV' => $this->sV,
'arrayClosure' => $this->fnA['test']['alice'],
//'propClosure' => $this->fnC,
];
}
function aT()
{
$fn = $this->fnA['test']['alice'];
return $fn().PHP_EOL;
}
function sT()
{
$fn = $this->fnC;
return $fn().PHP_EOL;
}
function compare(alice $__Test)
{
$r = [];
$r['alice'] = $this === $__Test;
$r['alice->fnA'] = $this->fnA === $__Test->fnA;
$r['alice->fnC'] = $this->fnC === $__Test->fnC;
$r['alice->__bob'] = $this->__bob === $__Test->__bob;
return $r;
}
}
$refTest = 'foooooooooooobar';
echo '#--start closure test', PHP_EOL;
$T = new Test('ORIG', new alice, $refTest, new DefaultObject);
$T->set('$T.ready');
$T->closureAsProperty(); // base name 'orig', alice name 'orig'
echo '#----should be the same as above', PHP_EOL;
$T->closureInArray(); // base name 'orig', alice name 'orig'
echo '#--create shallow copy $D', PHP_EOL;
$D = $T->shallowCopy();
$T->set('$T.afterShallowCopy');
$D->set('$D.afterShallowCopy');
$T->closureAsProperty(); // base name 'orig', alice name 'orig'
$D->closureAsProperty(); // base name 'orig', alice name 'orig'
echo '#----should be the same as above', PHP_EOL;
$T->closureInArray(); // base name 'orig', alice name 'orig'
$D->closureInArray(); // base name 'orig', alice name 'orig'
echo '#--change name of $D to "COPY"', PHP_EOL;
$D->setClassName('COPY');
$T->set('$T.afterNameChange$D');
$D->set('$D.afterNameChange$D');
echo '#----closure in ALICE returns COPY: because ORIG and COPY referencing to the same ALICE object', PHP_EOL;
$T->closureAsProperty(); // base name 'orig', alice name 'copy'
$D->closureAsProperty(); // base name 'copy', alice name 'copy'
echo '#----should be the same as above', PHP_EOL;
$T->closureInArray(); // base name 'orig', alice name 'copy'
$D->closureInArray(); // base name 'copy', alice name 'copy'
echo '#--create deep $E', PHP_EOL;
$E = $T->deepCopy();
$T->set('$T.afterDeepCopy');
$D->set('$D.afterDeepCopy');
$E->set('$E.afterDeepCopy');
echo '#----closure in ALICE returns COPY: because ORIG and COPY referencing to the same ALICE object', PHP_EOL;
$T->closureAsProperty(); // base name 'orig', alice name 'orig'
$D->closureAsProperty(); // base name 'orig', alice name 'orig'
$E->closureAsProperty(); // base name 'orig', alice name 'orig'
$T->closureInArray(); // base name 'orig', alice name 'orig'
$D->closureInArray(); // base name 'orig', alice name 'orig'
$E->closureInArray(); // base name 'orig', alice name 'orig'
echo '#--change name of $E to "DEEP"', PHP_EOL;
$E->setClassName('DEEP');
$T->set('$T.afterNameChange$E');
$D->set('$D.afterNameChange$E');
$E->set('$E.afterNameChange$E');
echo '#----closure in ALICE returns COPY: because ORIG and COPY referencing to the same ALICE object', PHP_EOL;
$T->closureAsProperty(); // base name 'orig', alice name 'orig'
$D->closureAsProperty(); // base name 'orig', alice name 'orig'
echo '#----both should be DEEP', PHP_EOL;
$E->closureAsProperty(); // base name 'orig', alice name 'orig'
echo '#----should be the same as above', PHP_EOL;
$T->closureInArray(); // base name 'orig', alice name 'orig'
$D->closureInArray(); // base name 'orig', alice name 'orig'
$E->closureInArray(); // base name 'orig', alice name 'orig'
var_dump($T->compare($D));
var_dump($T->compare($E));
echo '#--dump of "ORIG" ############################################################################', PHP_EOL;
var_dump($T);
echo '#--dump of "COPY" ############################################################################', PHP_EOL;
var_dump($D);
echo '#--dump of "DEEP" ############################################################################', PHP_EOL;
var_dump($E);
// output:
/*
#--start closure test
closure as property:base.sv.propertyClosure.ORIG.$T.ready
alic.sv.propertyClosure.ORIG.$T.ready
#----should be the same as above
closure in array: base.av.arrayClosure.ORIG.$T.ready
alic.av.arrayClosure.ORIG.$T.ready
#--create shallow copy $D
closure as property:base.sv.propertyClosure.ORIG.$T.afterShallowCopy
alic.sv.propertyClosure.ORIG.$D.afterShallowCopy
closure as property:base.sv.propertyClosure.ORIG.$D.afterShallowCopy
alic.sv.propertyClosure.ORIG.$D.afterShallowCopy
#----should be the same as above
closure in array: base.av.arrayClosure.ORIG.$T.afterShallowCopy
alic.av.arrayClosure.ORIG.$D.afterShallowCopy
closure in array: base.av.arrayClosure.ORIG.$D.afterShallowCopy
alic.av.arrayClosure.ORIG.$D.afterShallowCopy
#--change name of $D to "COPY"
#----closure in ALICE returns COPY: because ORIG and COPY referencing to the same ALICE object
closure as property:base.sv.propertyClosure.ORIG.$T.afterNameChange$D
alic.sv.propertyClosure.COPY.$D.afterNameChange$D
closure as property:base.sv.propertyClosure.COPY.$D.afterNameChange$D
alic.sv.propertyClosure.COPY.$D.afterNameChange$D
#----should be the same as above
closure in array: base.av.arrayClosure.ORIG.$T.afterNameChange$D
alic.av.arrayClosure.COPY.$D.afterNameChange$D
closure in array: base.av.arrayClosure.COPY.$D.afterNameChange$D
alic.av.arrayClosure.COPY.$D.afterNameChange$D
#--create deep $E
#----closure in ALICE returns COPY: because ORIG and COPY referencing to the same ALICE object
closure as property:base.sv.propertyClosure.ORIG.$T.afterDeepCopy
alic.sv.propertyClosure.COPY.$D.afterDeepCopy
closure as property:base.sv.propertyClosure.COPY.$D.afterDeepCopy
alic.sv.propertyClosure.COPY.$D.afterDeepCopy
closure as property:base.sv.propertyClosure.ORIG.$E.afterDeepCopy
alic.sv.propertyClosure.ORIG.$E.afterDeepCopy
closure in array: base.av.arrayClosure.ORIG.$T.afterDeepCopy
alic.av.arrayClosure.COPY.$D.afterDeepCopy
closure in array: base.av.arrayClosure.COPY.$D.afterDeepCopy
alic.av.arrayClosure.COPY.$D.afterDeepCopy
closure in array: base.av.arrayClosure.ORIG.$E.afterDeepCopy
alic.av.arrayClosure.ORIG.$E.afterDeepCopy
#--change name of $E to "DEEP"
#----closure in ALICE returns COPY: because ORIG and COPY referencing to the same ALICE object
closure as property:base.sv.propertyClosure.ORIG.$T.afterNameChange$E
alic.sv.propertyClosure.COPY.$D.afterNameChange$E
closure as property:base.sv.propertyClosure.COPY.$D.afterNameChange$E
alic.sv.propertyClosure.COPY.$D.afterNameChange$E
#----both should be DEEP
closure as property:base.sv.propertyClosure.DEEP.$E.afterNameChange$E
alic.sv.propertyClosure.DEEP.$E.afterNameChange$E
#----should be the same as above
closure in array: base.av.arrayClosure.ORIG.$T.afterNameChange$E
alic.av.arrayClosure.COPY.$D.afterNameChange$E
closure in array: base.av.arrayClosure.COPY.$D.afterNameChange$E
alic.av.arrayClosure.COPY.$D.afterNameChange$E
closure in array: base.av.arrayClosure.DEEP.$E.afterNameChange$E
alic.av.arrayClosure.DEEP.$E.afterNameChange$E
array(1) {
["Compare ORIG with COPY"]=>
array(5) {
["Test"]=>
bool(false)
["Test->fnA"]=>
bool(false)
["Test->fnC"]=>
bool(false)
["Test->alice"]=>
array(4) {
["alice"]=>
bool(true)
["alice->fnA"]=>
bool(true)
["alice->fnC"]=>
bool(true)
["alice->__bob"]=>
bool(true)
}
["Test::static"]=>
bool(true)
}
}
array(1) {
["Compare ORIG with DEEP"]=>
array(5) {
["Test"]=>
bool(false)
["Test->fnA"]=>
bool(false)
["Test->fnC"]=>
bool(false)
["Test->alice"]=>
array(4) {
["alice"]=>
bool(false)
["alice->fnA"]=>
bool(false)
["alice->fnC"]=>
bool(false)
["alice->__bob"]=>
bool(false)
}
["Test::static"]=>
bool(true)
}
}
#--dump of "ORIG" ############################################################################
object(web\test)#2 (6) {
["name"]=>
string(4) "ORIG"
["private"]=>
string(16) "foooooooooooobar"
["alice"]=>
object(web\alice)#3 (1) {
["arrayClosure"]=>
object(Closure)#4 (1) {
["this"]=>
object(web\alice)#3 (1) {
["arrayClosure"]=>
*RECURSION*
}
}
}
["static"]=>
object(ILLI\Core\Std\DefaultObject)#7 (0) {
}
["arrayClosure"]=>
object(Closure)#8 (1) {
["this"]=>
object(web\test)#2 (6) {
["name"]=>
string(4) "ORIG"
["private"]=>
string(16) "foooooooooooobar"
["alice"]=>
object(web\alice)#3 (1) {
["arrayClosure"]=>
object(Closure)#4 (1) {
["this"]=>
object(web\alice)#3 (1) {
["arrayClosure"]=>
*RECURSION*
}
}
}
["static"]=>
object(ILLI\Core\Std\DefaultObject)#7 (0) {
}
["arrayClosure"]=>
*RECURSION*
["propClosure"]=>
object(Closure)#9 (1) {
["this"]=>
object(web\test)#2 (6) {
["name"]=>
string(4) "ORIG"
["private"]=>
string(16) "foooooooooooobar"
["alice"]=>
object(web\alice)#3 (1) {
["arrayClosure"]=>
object(Closure)#4 (1) {
["this"]=>
object(web\alice)#3 (1) {
["arrayClosure"]=>
*RECURSION*
}
}
}
["static"]=>
object(ILLI\Core\Std\DefaultObject)#7 (0) {
}
["arrayClosure"]=>
*RECURSION*
["propClosure"]=>
*RECURSION*
}
}
}
}
["propClosure"]=>
object(Closure)#9 (1) {
["this"]=>
object(web\test)#2 (6) {
["name"]=>
string(4) "ORIG"
["private"]=>
string(16) "foooooooooooobar"
["alice"]=>
object(web\alice)#3 (1) {
["arrayClosure"]=>
object(Closure)#4 (1) {
["this"]=>
object(web\alice)#3 (1) {
["arrayClosure"]=>
*RECURSION*
}
}
}
["static"]=>
object(ILLI\Core\Std\DefaultObject)#7 (0) {
}
["arrayClosure"]=>
object(Closure)#8 (1) {
["this"]=>
object(web\test)#2 (6) {
["name"]=>
string(4) "ORIG"
["private"]=>
string(16) "foooooooooooobar"
["alice"]=>
object(web\alice)#3 (1) {
["arrayClosure"]=>
object(Closure)#4 (1) {
["this"]=>
object(web\alice)#3 (1) {
["arrayClosure"]=>
*RECURSION*
}
}
}
["static"]=>
object(ILLI\Core\Std\DefaultObject)#7 (0) {
}
["arrayClosure"]=>
*RECURSION*
["propClosure"]=>
*RECURSION*
}
}
["propClosure"]=>
*RECURSION*
}
}
}
#--dump of "COPY" ############################################################################
object(web\test)#12 (6) {
["name"]=>
string(4) "COPY"
["private"]=>
string(16) "foooooooooooobar"
["alice"]=>
object(web\alice)#3 (1) {
["arrayClosure"]=>
object(Closure)#4 (1) {
["this"]=>
object(web\alice)#3 (1) {
["arrayClosure"]=>
*RECURSION*
}
}
}
["static"]=>
object(ILLI\Core\Std\DefaultObject)#7 (0) {
}
["arrayClosure"]=>
object(Closure)#29 (1) {
["this"]=>
object(web\test)#12 (6) {
["name"]=>
string(4) "COPY"
["private"]=>
string(16) "foooooooooooobar"
["alice"]=>
object(web\alice)#3 (1) {
["arrayClosure"]=>
object(Closure)#4 (1) {
["this"]=>
object(web\alice)#3 (1) {
["arrayClosure"]=>
*RECURSION*
}
}
}
["static"]=>
object(ILLI\Core\Std\DefaultObject)#7 (0) {
}
["arrayClosure"]=>
*RECURSION*
["propClosure"]=>
object(Closure)#30 (1) {
["this"]=>
object(web\test)#12 (6) {
["name"]=>
string(4) "COPY"
["private"]=>
string(16) "foooooooooooobar"
["alice"]=>
object(web\alice)#3 (1) {
["arrayClosure"]=>
object(Closure)#4 (1) {
["this"]=>
object(web\alice)#3 (1) {
["arrayClosure"]=>
*RECURSION*
}
}
}
["static"]=>
object(ILLI\Core\Std\DefaultObject)#7 (0) {
}
["arrayClosure"]=>
*RECURSION*
["propClosure"]=>
*RECURSION*
}
}
}
}
["propClosure"]=>
object(Closure)#30 (1) {
["this"]=>
object(web\test)#12 (6) {
["name"]=>
string(4) "COPY"
["private"]=>
string(16) "foooooooooooobar"
["alice"]=>
object(web\alice)#3 (1) {
["arrayClosure"]=>
object(Closure)#4 (1) {
["this"]=>
object(web\alice)#3 (1) {
["arrayClosure"]=>
*RECURSION*
}
}
}
["static"]=>
object(ILLI\Core\Std\DefaultObject)#7 (0) {
}
["arrayClosure"]=>
object(Closure)#29 (1) {
["this"]=>
object(web\test)#12 (6) {
["name"]=>
string(4) "COPY"
["private"]=>
string(16) "foooooooooooobar"
["alice"]=>
object(web\alice)#3 (1) {
["arrayClosure"]=>
object(Closure)#4 (1) {
["this"]=>
object(web\alice)#3 (1) {
["arrayClosure"]=>
*RECURSION*
}
}
}
["static"]=>
object(ILLI\Core\Std\DefaultObject)#7 (0) {
}
["arrayClosure"]=>
*RECURSION*
["propClosure"]=>
*RECURSION*
}
}
["propClosure"]=>
*RECURSION*
}
}
}
#--dump of "DEEP" ############################################################################
object(web\test)#26 (6) {
["name"]=>
string(4) "DEEP"
["private"]=>
string(16) "foooooooooooobar"
["alice"]=>
object(web\alice)#34 (1) {
["arrayClosure"]=>
object(Closure)#45 (1) {
["this"]=>
object(web\alice)#34 (1) {
["arrayClosure"]=>
*RECURSION*
}
}
}
["static"]=>
object(ILLI\Core\Std\DefaultObject)#7 (0) {
}
["arrayClosure"]=>
object(Closure)#44 (1) {
["this"]=>
object(web\test)#26 (6) {
["name"]=>
string(4) "DEEP"
["private"]=>
string(16) "foooooooooooobar"
["alice"]=>
object(web\alice)#34 (1) {
["arrayClosure"]=>
object(Closure)#45 (1) {
["this"]=>
object(web\alice)#34 (1) {
["arrayClosure"]=>
*RECURSION*
}
}
}
["static"]=>
object(ILLI\Core\Std\DefaultObject)#7 (0) {
}
["arrayClosure"]=>
*RECURSION*
["propClosure"]=>
object(Closure)#43 (1) {
["this"]=>
object(web\test)#26 (6) {
["name"]=>
string(4) "DEEP"
["private"]=>
string(16) "foooooooooooobar"
["alice"]=>
object(web\alice)#34 (1) {
["arrayClosure"]=>
object(Closure)#45 (1) {
["this"]=>
object(web\alice)#34 (1) {
["arrayClosure"]=>
*RECURSION*
}
}
}
["static"]=>
object(ILLI\Core\Std\DefaultObject)#7 (0) {
}
["arrayClosure"]=>
*RECURSION*
["propClosure"]=>
*RECURSION*
}
}
}
}
["propClosure"]=>
object(Closure)#43 (1) {
["this"]=>
object(web\test)#26 (6) {
["name"]=>
string(4) "DEEP"
["private"]=>
string(16) "foooooooooooobar"
["alice"]=>
object(web\alice)#34 (1) {
["arrayClosure"]=>
object(Closure)#45 (1) {
["this"]=>
object(web\alice)#34 (1) {
["arrayClosure"]=>
*RECURSION*
}
}
}
["static"]=>
object(ILLI\Core\Std\DefaultObject)#7 (0) {
}
["arrayClosure"]=>
object(Closure)#44 (1) {
["this"]=>
object(web\test)#26 (6) {
["name"]=>
string(4) "DEEP"
["private"]=>
string(16) "foooooooooooobar"
["alice"]=>
object(web\alice)#34 (1) {
["arrayClosure"]=>
object(Closure)#45 (1) {
["this"]=>
object(web\alice)#34 (1) {
["arrayClosure"]=>
*RECURSION*
}
}
}
["static"]=>
object(ILLI\Core\Std\DefaultObject)#7 (0) {
}
["arrayClosure"]=>
*RECURSION*
["propClosure"]=>
*RECURSION*
}
}
["propClosure"]=>
*RECURSION*
}
}
}
Comments