Let's say we have a class stockFns and I do
$stockFns->{$functionOne}=create_function('$a,$b' , 'return $a+$b;');
This creates a property in $stockFns named whatever create_function returned.
Now I want to refer (invoke) to the created_function.
What would be a clean way to do it in a single instruction?. An example
$stockFns=new StockFns;
$functionOne='add';
$stockFns->{$functionOne}=create_function('$a,$b' , 'return $a+$b;');
//echo "***" . ($stockFns->add)(1,2); // That doesn't work
$theFn=$stockFns->add;
echo $theFn(1,2); // This works but reuires two instructions
Thanks!
Either your way, or
echo call_user_func(array($stockFbs, 'add'), 1, 2);
The problem is, that PHP cannot distinguish real methods from properties with callables. If you call something with () it will not touch the properties at all and in maybe will call __call, if it exists. You can try something like
class StockFns {
public function __call ($name, $args) {
$fctn = $this->{$name};
return call_user_func_array($fctn, $args);
}
}
As a workaround, so __call() will redirect to your callback.
have you tried call_user_func?
http://php.net/manual/en/function.call-user-func.php
echo call_user_func(array($stockFns, $functionOne), 1, 2);
if you're using PHP5.3 and up, you should really consider using anonymous function
http://my.php.net/manual/en/functions.anonymous.php
Related
I am having some issues with my function which returns an array, I decided to try and use an OO approach to my php code and try to make a class with a few static functions since I decided I don't want to access it using an object. In my code, within the same class, I decided to make the following function:
public static function decideCategory($tweets) {
$tweet = $tweets;
if(in_array($tweet, self::$food)) {
echo "\nOur " . $tweet . " is under food\n";
} //if statements of the same nature below as well.
}
Now, this function works in the sense that it does not throw an error where $food is definded as an array at the top. However, originally I simply had $food defined at the top as just a private static variable, and then I had the following function which I passed into the in_array.
public static function getFood()
{
self::$food = array("Wendys", "McDonalds", "Wendy's", "Chic Fil A", "Chic-Fil-a", "Burger", "TGI", "BBQ", "Grilling", "Wine", "Tasty", "Yum", "IHOP", "Pancakes", "Pizza", "Cake"
,"Baking");
return self::$food;
}
However, it would return an error saying that in_array expects an array value for its second argument, but that instead it sees that a null was passed instead. Why is that and how can I use methods to do my comparison rather than the variables themselvs. If this were Java this would be how I would do it, and as such I cannot see why php would have these issues as it appears to follow a similar logic with returns.
Yes it would error because until you call self::getFood() Self::$food is null if you have declared it as
static $food;
update your method as below
public static function decideCategory($tweets)
{
$tweet = $tweets;
$food = self::getFood();
if(in_array($tweet, $food)) {
echo "\nOur " . $tweet . " is under food\n";
} //if statements of the same nature below as well.
}
how to define function name (in PHP) using variable, like this?
$a='myFuncion';
function $a() {.......}
or like that?
The only way I know to give a fixed name to a function is to use eval, which I would not suggest.
More likely, what you want is to stuff a function IN a variable, and then just call that.
Try this:
$a = function() {
echo 'This is called an anonymous function.';
}
$a();
EDIT:
If you want to be accessible from other files, then use GLOBAL variable:
$GLOBALS['variable_name'] = 'my_func_123';
${$GLOBALS['variable_name']} = function() {
echo 'This is called an anonymous function.';
};
// Executing my_func_123()
${$GLOBALS['variable_name']}();
See also: http://php.net/manual/en/functions.anonymous.php
I have a problem to test a Method like that
public function index(){
if($this->request->is('get')){
if($this->Session->check('saveConflict')){
$this->set('conflict',true);
}else{
$this->set('data','test');
}
if($this->Session->check('full')){
$this->set('data',$this->Model->find('all'));
}else{
$this->set('data','test');
}
}else{
throw new BadRequestException;
}
}
unless that method maybe doesn't make sense, here is my problem. I have to call the method "check" on the Session-Component twice. But I want that for example the first methode mock-call retruns a "false" and the second a "true".
Here's what I have
$this->Editors->Session
->expects($this->once())
->method('check')
->will($this->returnValue(true));
I've tried it with the expectation "$this->at(1)" the call via order-index. But i think that isnt pretty clever because if I add a Session->check anywhere in the interpreted way though my base-method for example i have to change all those test-lines to make it work properly again.
I use CakePHP 2.4.6 and php-unit 4.1.3.
Is there any other why to do what I want to do?
Use the
->will($this->onConsecutiveCalls(array('return_value1',
'retur_value2',
...)));
Give the sequence of the return value in the order you want, the mocked method will return it in order.Or you can try the $this->returnCallback to do some sophisticated customize.You can find the example here How can I get PHPUnit MockObjects to return differernt values based on a parameter?.
Example
If you just want to do the unit test and cover all the path,I'll do like this:
public function testIndex()
{
....
$this->Editors->Session
->expects($this->any())
->method('check')
->will($this->returnCallback(array($this,'sessionCallback')));
$this->object->index();
$this->object->index();
.....
}
private $sessionFlag;
public function sessionCallback($value)
{
$rtnValue = $this->sessionFlag[$value];
$this->sessionFlag[$value] = (!$rtnValue);
return $rtnValue;
}
Given this class:
class Tacobell{
public function order_taco(){
echo "3 Tacos, thank you.";
}
public function order_burrito(){
echo "Cheesy bean and rice, please";
}
}
$lunch = new Tacobell;
$lunch->order_burrito();
$lunch->order_taco();
How would I do something like this?
$myOrder = 'burrito';
$lunch->order_.$myOrder;
Obviously that code is bunk--but shows what I'm attempting to do better than trying to explain it away.
And maybe I'm going about this all wrong. I thought about a method with a switch statement, pass in burrito or taco, then call the right method from there. But then I have to know the end from the beginning, and I may potentially have lots of methods and I'd rather not have to update the switch statement everytime.
Thanks!
How about something like this?
class Tacobell {
public function order_burrito() {
echo "Bladibla.\n";
}
public function order($item) {
if (method_exists($this, "order_$item")) {
$this->{'order_' . $item}();
} else {
echo "Go away, we don't serve $item here.\n";
}
}
}
You would call it using $lunch->order('burrito');, which looks much cleaner to me. It puts all the uglyness in the method Tacobell::order.
$lunch->{'order_' . $myOrder}();
I do agree the design is a little iffy, but that's how to do it at least.
I think call_user_func is what you're looking for:
http://us3.php.net/call_user_func
You can pass it the string you suggested. See example #3 for calling a method of a class.
simple enough
$order = 'order_burrito';
$lunch->$order();
How are callbacks written in PHP?
The manual uses the terms "callback" and "callable" interchangeably, however, "callback" traditionally refers to a string or array value that acts like a function pointer, referencing a function or class method for future invocation. This has allowed some elements of functional programming since PHP 4. The flavors are:
$cb1 = 'someGlobalFunction';
$cb2 = ['ClassName', 'someStaticMethod'];
$cb3 = [$object, 'somePublicMethod'];
// this syntax is callable since PHP 5.2.3 but a string containing it
// cannot be called directly
$cb2 = 'ClassName::someStaticMethod';
$cb2(); // fatal error
// legacy syntax for PHP 4
$cb3 = array(&$object, 'somePublicMethod');
This is a safe way to use callable values in general:
if (is_callable($cb2)) {
// Autoloading will be invoked to load the class "ClassName" if it's not
// yet defined, and PHP will check that the class has a method
// "someStaticMethod". Note that is_callable() will NOT verify that the
// method can safely be executed in static context.
$returnValue = call_user_func($cb2, $arg1, $arg2);
}
Modern PHP versions allow the first three formats above to be invoked directly as $cb(). call_user_func and call_user_func_array support all the above.
See: http://php.net/manual/en/language.types.callable.php
Notes/Caveats:
If the function/class is namespaced, the string must contain the fully-qualified name. E.g. ['Vendor\Package\Foo', 'method']
call_user_func does not support passing non-objects by reference, so you can either use call_user_func_array or, in later PHP versions, save the callback to a var and use the direct syntax: $cb();
Objects with an __invoke() method (including anonymous functions) fall under the category "callable" and can be used the same way, but I personally don't associate these with the legacy "callback" term.
The legacy create_function() creates a global function and returns its name. It's a wrapper for eval() and anonymous functions should be used instead.
With PHP 5.3, you can now do this:
function doIt($callback) { $callback(); }
doIt(function() {
// this will be done
});
Finally a nice way to do it. A great addition to PHP, because callbacks are awesome.
Implementation of a callback is done like so
// This function uses a callback function.
function doIt($callback)
{
$data = "this is my data";
$callback($data);
}
// This is a sample callback function for doIt().
function myCallback($data)
{
print 'Data is: ' . $data . "\n";
}
// Call doIt() and pass our sample callback function's name.
doIt('myCallback');
Displays: Data is: this is my data
One nifty trick that I've recently found is to use PHP's create_function() to create an anonymous/lambda function for one-shot use. It's useful for PHP functions like array_map(), preg_replace_callback(), or usort() that use callbacks for custom processing. It looks pretty much like it does an eval() under the covers, but it's still a nice functional-style way to use PHP.
well... with 5.3 on the horizon, all will be better, because with 5.3, we'll get closures and with them anonymous functions
http://wiki.php.net/rfc/closures
You will want to verify whatever your calling is valid. For example, in the case of a specific function, you will want to check and see if the function exists:
function doIt($callback) {
if(function_exists($callback)) {
$callback();
} else {
// some error handling
}
}
create_function did not work for me inside a class. I had to use call_user_func.
<?php
class Dispatcher {
//Added explicit callback declaration.
var $callback;
public function Dispatcher( $callback ){
$this->callback = $callback;
}
public function asynchronous_method(){
//do asynch stuff, like fwrite...then, fire callback.
if ( isset( $this->callback ) ) {
if (function_exists( $this->callback )) call_user_func( $this->callback, "File done!" );
}
}
}
Then, to use:
<?php
include_once('Dispatcher.php');
$d = new Dispatcher( 'do_callback' );
$d->asynchronous_method();
function do_callback( $data ){
print 'Data is: ' . $data . "\n";
}
?>
[Edit]
Added a missing parenthesis.
Also, added the callback declaration, I prefer it that way.
For those who don't care about breaking compatibility with PHP < 5.4, I'd suggest using type hinting to make a cleaner implementation.
function call_with_hello_and_append_world( callable $callback )
{
// No need to check $closure because of the type hint
return $callback( "hello" )."world";
}
function append_space( $string )
{
return $string." ";
}
$output1 = call_with_hello_and_append_world( function( $string ) { return $string." "; } );
var_dump( $output1 ); // string(11) "hello world"
$output2 = call_with_hello_and_append_world( "append_space" );
var_dump( $output2 ); // string(11) "hello world"
$old_lambda = create_function( '$string', 'return $string." ";' );
$output3 = call_with_hello_and_append_world( $old_lambda );
var_dump( $output3 ); // string(11) "hello world"
I cringe every time I use create_function() in php.
Parameters are a coma separated string, the whole function body in a string... Argh... I think they could not have made it uglier even if they tried.
Unfortunately, it is the only choice when creating a named function is not worth the trouble.