use() statement on anonymous functions - php

Is it a bad practice to use it?
Because people say that global variables are bad practice and the use thing brings variables from outside into the functions, so it's like global
This is how it looks
$a = 1;
$func = function() use($a){
print $a;
};

Any arguments defined in the "use" arguments for an anonymous function use the value at the time when the anonymous function is defined; so they must exist at that point; but they don't need to be passed (or even exist in the caller scope) when the function is called.
function myFunctionCreator() {
$a = 1; // Must exist for the `use` clause
$func = function() use($a){
echo $a, PHP_EOL;
};
return $func;
}
$myFunc = myFunctionCreator();
$a = 2;
$myFunc(); // echoes 1 (value of $a at the point where the function was created)
As you can see from the above example, $a has a value of 1 at the point where the function is defined, and even though a variable with the same name exists at the point when the function called, it is the original $a (with the value 1) that is used in the function call.
Arguments defined in the main argument definition need not exist when the function is defined, but the values must be passed as arguments to the function at the point when it is called.
function myFunctionCreator() {
$a = 1; // Need not exist, and will be ignored
$func = function($a) {
echo $a, PHP_EOL;
};
return $func;
}
$myFunc = myFunctionCreator();
$value = 2;
$myFunc($value); // echoes 2 (value of $a explicitly passed to the function call
// at the time it is executed)
So the behaviour of the two types is quite different, and their purpose when combined provides a degree of flexibility that is quite different
As Rizier123 has mentioned in his comment, arguments passed to an anonymous function as "standard" can have defaults, typehints, etc, whereas "use" arguments cannot.
function myFunctionCreator() {
$func = function(array $dataset = [1,2,3]) {
foreach($dataset as $value) {
echo $value, PHP_EOL;
}
};
return $func;
}
$myFunc = myFunctionCreator();
$value = ['a','b','c'];
$myFunc($value);
$myFunc();
$myFunc(['x','y','z']);
Or (as the third call shows, arguments can be passed directly.
Andy of these applied to a "use" argument will result in a parse error

Related

Callback function not found while it is defined above

I have this code snippet that is supposed to find the differences between two arrays of feed items:
protected function execute()
{
$existingFeedItems = $feed->getItems();
$newFeedItems = $feed->loadItems();
function compareFeedItemIds($feedItem1, $feedItem2)
{
return $feedItem1->getFeedItemId() == $feedItem2->getFeedItemId() ? 0 : -1;
}
$feedItemsAdded = array_udiff($newFeedItems, $existingFeedItems, "compareFeedItemIds");
$feedItemsRemoved = array_udiff($existingFeedItems, $newFeedItems, "compareFeedItemIds");
$unchangedFeedItems = array_uintersect($newFeedItems, $existingFeedItems, "compareFeedItemIds");
}
This will throw the error:
Warning: array_udiff() expects parameter 3 to be a valid callback,
function 'compareFeedItemIds' not found or invalid function name
Even though I have defined that function above. What is the reason for PHP throwing this error? I have to add I am executing this from an object's method context.
If your callback function is defined within a namespace, then you need to indicate that namespace when you make the udiff() call.
$feedItemsAdded = array_udiff($newFeedItems, $existingFeedItems, "namespace\\compareFeedItemIds");
Otherwise PHP will search for the callback function in the global namespace
Let's assume having a local function definition and/or lambda function really is a good idea (it get's way less attractive if you have the same function definiton a couple of times scattered over your project ....).
You can define a function within another function/method and this defintion only takes place when execution of the script(s) reaches this code. But: The function definition isn't local; it bubbles up - outside of the function/class. And because of that you will get a "cannot redeclare function compareFeedItemIds" error if you execute execute() more than once.
There are several options to "fix" that.
You can assign the function to a local variable and then pass that variable as the third parameter to the array_* functions.
$compareFeedItemIds = function($feedItem1, $feedItem2) {
return $feedItem1->getFeedItemId() == $feedItem2->getFeedItemId() ? 0 : -1;
};
$feedItemsAdded = array_udiff($newFeedItems, $existingFeedItems, $compareFeedItemIds);
$feedItemsRemoved = array_diff($existingFeedItems, $newFeedItems, $compareFeedItemIds);
....
You can also store that function in an instance variable ...or a static class member.
Or... to avoid the namspace problem, just create a static method in your class and then reference that method via self::methodname or static::methodname like e.g.
<?php
class Foo {
public function bar() {
$a = [1,2,3];
$b = [2,3,4];
var_export( array_udiff($a, $b, 'self::moo') );
var_export( array_udiff($b, $a, 'self::moo') );
var_export( array_uintersect($a, $b, 'self::moo') );
}
protected static function moo($a,$b) {
return $a<=>$b;
}
}
$foo = new Foo;
$foo->bar();

What is the use for the argument block in anonymous functions

In this example:
$foo = function () use (){
// ^---------^ what is the use?
}
Aside this from being a function that we can use the use () part to import a data into the function, just like a regular function as in:
function bar ($foo){
}
but I don't understand what the function () part can be used for?
e.g:
$a = 1;
$foo = function ($b, $c) use ($a)
{
echo $a . PHP_EOL;
echo $b . PHP_EOL;
echo $c . PHP_EOL;
};
$foo(2, 3);
$a = 5;
$foo(7, 8);
Would output:
1
2
3
1
7
8
$b, $c - would be parameters you pass on execution.
$a is bound/imported on creation. So if you change it after $foo definition it would not change.
The parameter block is for inputting parameters. So if I define
$foo = function($bar) use ($baz) {
return $bar + $baz;
}
and then I, say, pass $foo to another function or bind it to another class, I can do like
function bonk($bar, $foo) {
$baz = 4;
return $foo($bar);
}
and somewhere else call
// Returns 7
bonk(3, $foo);
One allows you to get the variable from context while the other must be passed in. For example, I have $baz available to me in the class that defines $bonk so I pass it in, but I don't yet know what $bar is going to be until it bonk gets called somewhere else with $bar passed in.
So ok let's say I'm a class called Cats and I have an object SiameseCat available to me. I have a method called doTheThing that takes a function and a parameter. It tells the cat what to do and optionally what to do it to. So it always has the same cat but depending on where I call it from, I can have the siamese cat do different verbs to different nouns, but I know it's my cat doing it because that's where I defined the cat.

Why must I pass as reference the anonymous function in recursive anonymous functions in PHP?

Works:
$t = function($x,$y) use (&$t){
...
}
Does not work:
$t = function($x,$y) use ($t){
...
}
Why must I pass the function itself as reference?
Maybe this will help:
$f = 42;
$f = function() use ($f)
{
var_dump($f);
};
$f();
That outputs 42.
The use() is hit before the function is defined and assigned to $f. So if you don't pass by reference, you are accessing the variable as it was before the function was created. In this case, 42. In your case, NULL.
By passing a reference, you'll get $f's value at the time the function is called, which will be the anonymous function as you are expecting (assuming you haven't reassigned $f).
Passing Reference variable means you are accessing same variable within that scope.
Reference variable points to the same variable that were previously created.
Example
<?php
$a = 10;
$b = &$a;
function change_b($pass)
{
$b = $pass++;
}
echo $b."<br />";
change_b(&$a);
echo $b;
?>
above code will output 10 and then 11.
Recursive function has to access the same resource over and over again and that is much more efficient than copying values.

PHP: Is it necessary to change variable names when passing them to a function?

I have a body function and a function called within the first one.
As can be seen below I don't change the parameters name while using in the second function.
Is it necessary to change the params names for use inside _display_bar();? What are the side effects if I don't?
function main_func($form, &$form_state, $key, $code) {
$output = '';
...
$output .= _display_navbar($trans, $status_names);
return $output
}
function _display_navbar($trans, $status_names) {
$trans = 'bla';
$status_names = 'another bla';
$bar = $trans . ':' .$status_names;
return $bar;
};
Variables have function scope. Unless you specifically declare otherwise, the names are only valid inside the function. They do not bleed into other scopes. There are no side effects. You don't need to use unique names.
It actually does not matter. But you better should not have the same names - it is confusing. Let me give you an example. $s will have 3 after the first function call to sum; 7 after the second function call to sum. The parameters did not have the same name as the function parameter names.
To answer your question fully - there are absolutely no side effects.
function main()
{
$a = 1;
$b = 2;
$s = sum($a, $b);
$d = 3;
$e = 4;
$s = sum($d, $e);
}
function sum($first, $second)
{
$ret = $first + $second;
return $ret;
}
Once a variable is passed to a function, the name of the variable is not important. Only the data is passed through. So your function could be this:
function _display_navbar($foo, $bar) {
$foo = 'bla';
return $bar;
}
And it will return what ever was passed as the second parameter regardless of what the variable name was.
The names you pass as function arguments must be in scope at the point they are called.
It doesn't matter if they have the same name as the formal function parameters, but you must recognise that just because they have the same name doesn't mean that brings them into scope.
So, in your code:
function main_func($form, &$form_state, $key, $code) {
$output = '';
...
$output .= _display_navbar($trans, $status_names);
the last line will be incorrect, unless $trans and $status_names are in scope at the time.

How to call the current anonymous function in PHP?

I have an anonymous function which is supposed to call itself. However, I have no variable or function name at hand, so I was hoping to find a function that could do return "this" in context of functions. Is there such a thing?
Here's an example:
$f = function() use($bar, $foo) {
// call this function again.
};
Calling like this:
call_user_func(__FUNCTION__);
Leads to this:
Warning: call_user_func() expects parameter 1 to be a valid callback,
function '{closure}' not found or invalid function name
If I try to put $f in the use-list, then it says the variable is not defined (because it is not yet).
__FUNCTION__ cannot be used in anonymous functions
Pass the variable holding the anonymous function as a reference in the 'use' clause....
$f = function() use($bar, $foo, &$f) {
$f();
};
Tip of the hat to this answer.
Okay, I found out the way to do this:
$f = function() use(&$f) {
$f();
};
$f();
The key thing is to pass $f as a reference. Thus PHP does not try to pass a value but a reference to a memory slot.
I have an anonymous function which is supposed to call itself.
I prefer to use call_user_func_array(__FUNCTION__, $params); when calling a recursive function.
As your example doesn't have any arguments then i guess call_user_func(__FUNCTION__); would be better suited.
You would expect and hope the following code would work but that would be too easy.
$bar = 10;
$foo = 0;
$f = function() use (&$bar,$foo) {
if($bar){ // condition needed to prevent infinite loop
echo $bar-- . PHP_EOL;
call_user_func(__FUNCTION__); // wont work
}
};
$f();
The __FUNCTION__ "Magic constant" is unavailable to closures so the code needs to be adapted to allow the passing of the function variable. we can make the function available by passing it as a regular argument or via the use statement.
Function passed as argument
$bar = 10;
$foo = 0;
$f = function( $__FUNCTION__ = null ) use (&$bar, $foo) {
if($__FUNCTION__ && $bar){
echo $bar-- . PHP_EOL;
call_user_func( $__FUNCTION__, $__FUNCTION__);
}
};
$f ( $f );
Function passed via use statement
$bar = 10;
$foo = 0;
$__FUNCTION__ = function() use (&$bar, $foo, &$__FUNCTION__) {
if($bar){
echo $bar-- . PHP_EOL;
call_user_func( $__FUNCTION__ );
}
};
$__FUNCTION__();
Working example, click edit-> ideone it! to re-run code.
http://www.php.net/manual/en/language.constants.predefined.php
Edit: Posted before code was given. Of course it doesn't work on anonymous functions.
call_user_func(__FUNCTION__, $param1, $param2);
call_user_func_array(__FUNCTION__, $params);
function i_dont_know() {
call_user_func(__FUNCTION__,$params);
//or
$funcname = __FUNCTION__;
$funcname($params);
}

Categories