Location: PHPKode > scripts > pClosure > pclosure/pClosure_test.php
<?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("");

?>
Return current item: pClosure