note 99721 modified in function.create-function by danbrown

From: Date: Wed, 01 Sep 2010 19:37:35 +0000
Subject: note 99721 modified in function.create-function by danbrown
References: 1  Groups: php.notes 
Request: Send a blank email to php-notes+get-172255@lists.php.net to get a copy of this message
If you create a function that will only be used from an object context (i.e. you want a dynamic method that can then call methods from the original object, still maintaining access to the object's runtime values) then you can use the following functions I have created (ob_lambda_func and ob_lambda) to enable the dynamic function to easily call *public* methods on the object, in their runtime contexts: <?php /* the OB Lambda functions allow a lambda function to call a method from its callee's object */ if(!function_exists('ob_lambda_func')){ function ob_lambda_func($method, $args) { if((phpversion()+0)<5.1 || (substr(phpversion(),2)+0)<1.1) die("\nError: This script requires PHP v5.1.1+!\n"); $bt=debug_backtrace(); foreach($bt as $xsp) { if(isset($xsp['object'])) { if(!method_exists($xsp['object'], $method)) continue; return call_user_func_array(array($xsp['object'], $method), $args); } } if(!function_exists($method)) die("\nOB: Internal Error! ($method)"); return call_user_func_array($method, $args); }} if(!function_exists('ob_lambda')){ function ob_lambda($method) { return create_function('','$args=func_get_args(); return ob_lambda_func('.var_export($method, true).',$args);'); }} /* Usage: * For each callable method, store the results of ob_lambda('method_name') * When a lambda function you call wants to access one of these methods, * you need to pass it the result of ob_lambda for that method, the easiest * way is to have one of the lambda functions arguments accept the result * i.e.: $myFunc=ob_lambda('myMethod'); * $lf1=create_function('$func', '$func( ... args ... )'); * $lf1($myFunc); * because create_function prepends a \0 to the function name, it is difficult * to pass the result of ob_lambda to the target function without using an argument */ /* here is an example -- lambda function Foo::test can call Foo::Bar and Foo::Baz, and these */ class Foo { private $bar, $baz, $test; private $runtimeValue=0; function __construct() { $this->runtimeValue=rand(); $this->bar=ob_lambda('Bar'); $this->baz=ob_lambda('Baz'); $this->test=create_function( '$bar, $baz', '$bar("Hello, World!"); $baz();' ); } function Test() { $fn=$this->test; $fn($this->bar, $this->baz); } function Bar($a) { echo "$a: Bar ($this->runtimeValue)\n"; } function Baz() { echo "and another! Baz ($this->runtimeValue)\n"; } } $foo=new Foo(); // Foo::Bar("Testing Other Method"); <-- this causes fatal error // (using $this when not in object context) $foo->Test(); ?> This snippet (with test) shows how the lambda function $foo->test can call Foo::Bar and Foo::Baz without an explicit reference to the original object. The methods are run from their object context, and so can access the runtime-modified variable $foo->runtimeValue, which is set to a random number on construction. The function definition for $foo->test is the following: function ($bar, $baz) { $bar("Hello, World!"); $baz; } As you can see, it is clean and simple, with no obvious artifacts from the use of OB Lambda The expected output should be: Hello, World!: Bar (440048505) and another! Baz (440048505) Or any other random number in place of 440048505 Make sure, before you change your code, that your target server has PHP 5.1.1+, or these functions won't work and will return an error! Hope this helps anyone as much as it has me! :) --was-- If you create a function that will only be used from an object context (i.e. you want a dynamic method that can then call methods from the original object, still maintaining access to the object's runtime values) then you can use the following functions I have created (ob_lambda_func and ob_lambda) to enable the dynamic function to easily call *public* methods on the object, in their runtime contexts: <?php /* the OB Lambda functions allow a lambda function to call a method from its callee's object */ if(!function_exists('ob_lambda_func')){ function ob_lambda_func($method, $args) { if((phpversion()+0)<5.1 || (substr(phpversion(),2)+0)<1.1) die("\nError: This script requires PHP v5.1.1+!\n"); $bt=debug_backtrace(); foreach($bt as $xsp) { if(isset($xsp['object'])) { if(!method_exists($xsp['object'], $method)) continue; call_user_func_array(array($xsp['object'], $method), $args); return; } } if(!function_exists($method)) die("\nOB: Internal Error! ($method)"); call_user_func_array($method, $args); }} if(!function_exists('ob_lambda')){ function ob_lambda($method) { return create_function('','$args=func_get_args(); ob_lambda_func('.var_export($method, true).',$args);'); }} /* Usage: * For each callable method, store the results of ob_lambda('method_name') * When a lambda function you call wants to access one of these methods, * you need to pass it the result of ob_lambda for that method, the easiest * way is to have one of the lambda functions arguments accept the result * i.e.: $myFunc=ob_lambda('myMethod'); * $lf1=create_function('$func', '$func( ... args ... )'); * $lf1($myFunc); * because create_function prepends a \0 to the function name, it is difficult * to pass the result of ob_lambda to the target function without using an argument */ /* here is an example -- lambda function Foo::test can call Foo::Bar and Foo::Baz, and these */ class Foo { private $bar, $baz, $test; private $runtimeValue=0; function __construct() { $this->runtimeValue=rand(); $this->bar=ob_lambda('Bar'); $this->baz=ob_lambda('Baz'); $this->test=create_function( '$bar, $baz', '$bar("Hello, World!"); $baz();' ); } function Test() { $fn=$this->test; $fn($this->bar, $this->baz); } function Bar($a) { echo "$a: Bar ($this->runtimeValue)\n"; } function Baz() { echo "and another! Baz ($this->runtimeValue)\n"; } } $foo=new Foo(); // Foo::Bar("Testing Other Method"); <-- this causes fatal error // (using $this when not in object context) $foo->Test(); ?> This snippet (with test) shows how the lambda function $foo->test can call Foo::Bar and Foo::Baz without an explicit reference to the original object. The methods are run from their object context, and so can access the runtime-modified variable $foo->runtimeValue, which is set to a random number on construction. The function definition for $foo->test is the following: function ($bar, $baz) { $bar("Hello, World!"); $baz; } As you can see, it is clean and simple, with no obvious artifacts from the use of OB Lambda The expected output should be: Hello, World!: Bar (440048505) and another! Baz (440048505) Or any other random number in place of 440048505 Make sure, before you change your code, that your target server has PHP 5.1.1+, or these functions won't work and will return an error! Hope this helps anyone as much as it has me! :) http://php.net/manual/en/function.create-function.php

« previous php.notes (#172255) next »