<?php
require_once 'pClosure.php';
//you have to go back 4 levels to actually get to where the code was that caused the error :(
//set_error_handler(pClosure::createFunction('$errno, $errstr, $errfile, $errline', '$debug = debug_backtrace(); print "\n\nError triggered on line {$debug[3][\'line\']}";'));
class A implements Countable, pClosureContext
{
const INTEGER_TEST = 256;
private $methods = array(), $int = 23;
public function __call($name, array $args)
{
//execute the closure's code with the context of this instance
if (isset($this->methods[$name]) && $this->methods[$name] instanceof pClosure)
{
return $this->methods[$name]->apply($this, $args);
}
}
public function callClosure(pClosure $__closure__, array $__args__)
{
$__returnValue__ = null;
extract($__args__, EXTR_OVERWRITE | EXTR_REFS);
try{
//evaluate the code in this context
$__returnValue__ = eval(preg_replace(pClosure::FUNC_GET_ARGS, '\\1$__args__;', $__closure__->code) . ' return null;');
}
catch (Exception $e)
{
$etype = get_class($e);
//throw a new Exception, that contains backtrace info
throw new $etype(
$e->getMessage() .
" and defined in '{$__closure__->trace[0]['file']}' on line {$__closure__->trace[0]['line']} : runtime-created closure",
$e->getCode()
);
}
return $__returnValue__;
}
public function __get ($name)
{
return $this->methods[$name];
}
public function __set ($name, $value)
{
//use this to add closures to be executed in __call
$this->methods[$name] = $value;
}
//implements Countable
public function count ()
{
return 12;
}
}
$instanceOfA = new A;
//add a method to the object to be executed in scope
$instanceOfA->test = new pClosure('', 'if (isset($secondaryProperty)) print $secondaryProperty; print "Access the private variable \$this->int = {$this->int}";');
echo "\n\nThe output of \$instanceOfA->test(): ", $instanceOfA->test();
$instanceOfA->test->secondaryProperty = 'NOTICE: the $secondaryProperty is now in the scope. ';
//create a closure that will take the object as an additional parameter
$test1 = pClosure::createClosure('', 'echo "\n\nThe output of \$x->test() which is an additional param of the closure: ", $x->test();',
array('x' => $instanceOfA));
$test2 = pClosure::createClosure('string &$string', '$string = "new value";');
$test3 = pClosure::createClosure('stdClass $a', 'echo "\n\nclass name of \$a in \$test3 = ", get_class($a);');
//$instanceOfA will pass checks for Countable, A, and object
$test4 = pClosure::createClosure('object $a', 'echo "\n\ntypeof \$a in \$test4 = ", gettype($a);');
$alsoPassedByReference = 34;
$returnVal = null;
//this closure takes two additional arguments (alsoPassedByReference and top) which will be extracted into the function context
$test5 = pClosure::createClosure('$d', '$alsoPassedByReference = 56; echo "\n\ntypeof \$d in \$test5 = ", gettype($d); $top = "\$test5 called";',
array('alsoPassedByReference' => &$alsoPassedByReference, 'top' => &$returnVal));
//
$test6 = pClosure::createClosure('$a = 0xFF, array $b=array(), stdClass $e = null', 'echo "\n\n\$a = $a ", "typeof \$e = ", gettype($e);');
//$instanceOfA will pass checks for Countable, A, and object
$test7 = pClosure::createClosure('Countable $a', 'echo "\n\n\$a in \$test7 implements Countable: ", count($a);');
$test8 = pClosure::createClosure('$a = A::INTEGER_TEST', 'echo "\n\n\$a in \$test8 = ", $a;');
$test8();
$test6();
$test1();
$test4($instanceOfA);
$test7($instanceOfA);
print "\n\n\$alsoPassedByReference before pass by reference as additional parameter: {$alsoPassedByReference}";
$test5(new stdClass);
print "\n\n\$returnVal after pass by reference: {$returnVal}";
print "\n\n\$alsoPassedByReference after pass by reference as additional parameter: {$alsoPassedByReference}";
$test3(new stdClass);
$val = "ret";
print "\n\n\$val before pass by reference: {$val}";
$test2($val);
print "\n\n\$val after pass by reference: {$val}";
$val = 1;
print "\n\n\$val set to an integer: {$val}";
print "\n\nThis next call will trigger an exception because \$test2's first argument must be a string: ";
try{
$test2($val);
}
catch(InvalidArgumentException $e)
{
echo "\n\nException triggered because integer was passed for parameter that requires string";
}
print "\n\nThis next call will trigger an error because \$test5's first argument is required: ";
$test5();
print "\n\n\$val after pass by reference: {$val}";
print "\n\nThis next call will trigger a fatal error because \$test2's first argument must be passed by reference: \n";
$test2("");
?>
|