<?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("");
 
 
?>
 
 
 |