PHP anonymous function before 5.3 - array_walk - php

Is it possible to use PHP array_walk with an anonymous function (before PHP 5.3)? or some workaround..
I'm using array_walk inside a public class method and I don't want to define a PHP function.. I want to do something like:
array_walk($array, function($value) {...});
If that's not possible is it possible to use a class method instead of a function?

Use create_function.
array_walk($array, create_function('&$v, $k', '$v...'));

Yes, you can pass an array as second parameter, containing the object and the method name as string:
class Foo {
public function a($a) {
array_walk($a, array($this, 'b'));
}
private function b($v, $k) {
print $v;
}
}
$f = new Foo();
$f->a(array('foo', 'bar'));
prints
foobar
The signature of the array_walk() (can be found in the documentation), defines the second argument as callback, for which the following description can be found:
A PHP function is passed by its name as a string. Any built-in or user-defined function can be used, except language constructs such as: array(), echo(), empty(), eval(), exit(), isset(), list(), print() or unset().
A method of an instantiated object is passed as an array containing an object at index 0 and the method name at index 1.
Static class methods can also be passed without instantiating an object of that class by passing the class name instead of an object at index 0.
Apart from common user-defined function, create_function() can also be used to create an anonymous callback function. As of PHP 5.3.0 it is possible to also pass a closure to a callback parameter.

It's possible using create_function().
Stolen from the manual:
<?php
$av = array("the ", "a ", "that ", "this ");
array_walk($av, create_function('&$v,$k', '$v = $v . "mango";'));
print_r($av);
?>

To answer the second portion (the first has been answered well enough I think, although I never really liked create_function):
If that's not possible is it possible to use a class method instead of a function?
Yes, pass array($instance,'methodname') or array('classname','methodname') for object methods and static methods respectively.

Related

PHP: Is there a difference in passing a variable to anonymous function, and using closure function?

I understand what both Lambda and Closure functions represent, but I don't understand the need for Closure functions.
What's the need for Closure functions if we can just pass the variable to the Lambda functions. It looks like it's easier to write the variable name when calling the function, than writing 'use' and then defining it.
For example, these two will do exactly the same:
$string = 'string';
$lambda = function($string) {
echo $string;
};
$lambda($string);
$string = 'string';
$closure = function() use ($string) {
echo $string;
};
$closure();
...and in my understanding, the first block of code is Anonymous (Lambda) function, and the second one is Closure. Also, changing the variable inside the function will not affect the variable outside of it in both ways.
I've found a lot of questions about the differences, but none of them explained the need for it.
Thank you for answers.
The closure function is useful when you don't have control over the arguments that are being passed. For instance, when you use array_map you can't add an additional parameter, it just receives the array elements. You can use the closure to access additional variables.
$string = "foo";
$array = ["abc", "def"];
$new_array = array_map(function($x) use ($string) {
return $string . $x;
}, $array);
Anonymous functions, also known as closures, allow the creation of
functions which have no specified name. They are most useful as the
value of callback parameters, but they have many other uses. Anonymous
functions are implemented using the Closure class.
echo preg_replace_callback('~-([a-z])~', function ($match) {
return strtoupper($match[1]);
}, 'hello-world');
// outputs helloWorld
Closures may also inherit variables from the parent scope. Any such
variables must be passed to the use language construct. From PHP 7.1,
these variables must not include superglobals, $this, or variables
with the same name as a parameter.

PHP - Passing a variable to a function without passing variables asked before it?

Is it possible to pass a variable to function without passing the variables that come before it in the function definition?
For example, if my function looks like this:
function doThis( $v1, $v2, $v3 )
{
echo $v1.$v2.$v3;
}
Can I then call the function with only some of those variables, like doThis("v1",null,"v3") or some other way?
you can use predefined arguments:
function doThis( $v1, $v2 = "hello", $v3 = 1 ) {}
call to this function only with the first argument, the 2nd and 3rd will be "hello",1 by defualt:
doThis(10);
+1 on #Alon post
You can also use an array ..
$array['var1'] = null;
$array['var2'] = "foo";
$array['var3'] = "bar";
doThis($array);
function doThis($theArray){
var_dump($theArray);
}
This way, you can use empty values and N amout of variables.
Yes, you can do doThis("v1",null,"v3"), if you prepare your function to handle that null argument.
For example your example will work just fine.
Or, if it makes sense you can change the order of the arguments so you can set defaults.
You can specify default values in the function definition like so:
function doThis($a, $b=null, $c=null) {
echo $a . $b . $c;
}
doThis("hello", " world"); // yields: hello world
In this function, $a is a required parameter. The other two values are optional.
To appease the commenter below, you can of course still call this function like so:
doThis("hello", null, "world");
and of course, you do not have to provide defaults (but it is a good idea to do so)
The answer is: rework your workflow.
I know you don't like that answer, but honestly, if you are passing more than 3 parameters or if sometimes you don't want to pass part of the beginning parameters, you probably want to rethink what you're doing. Function and method calls should be simple. You are probably doing too much in your function.
General tips:
Use classes if appropriate. This way you can avoid passing some information around because it's stored in the class and your methods have access to it.
Keep methods cohesive. That means your methods and functions should do one thing and do it well.
Put variables you want to pass only sometimes at the back. This allows you to simply not pass them if they have $var=null after it. You then check to see if $var===null before doing something with it.
Much cleaner way is passing an array of variables, as demonstrated by #jflaflamme.
Another way is allowing an arbitrary number of variables like this:
function foo()
{
$arguments = func_get_args();
if(sizeof($arguments))
{
echo implode('', $arguments);
}
}
foo(1, 2, 3, $some_var);
You can also loop trough the array you obtain via func_get_args, check them for their type (if it's a null, array, object - you name it) and then handle them in a way you deem appropriate.

Trying to understand odd variant of a PHP array_map() call [duplicate]

This question already has answers here:
How to use class methods as callbacks
(5 answers)
Closed 10 months ago.
I'm trying to understand some code I found the open source oauth-php library. The relevant code snippet is:
protected function sql_printf ( $args )
{
$sql = array_shift($args);
if (count($args) == 1 && is_array($args[0]))
{
$args = $args[0];
}
$args = array_map(array($this, 'sql_escape_string'), $args);
return vsprintf($sql, $args);
}
Where $args is an array of arguments that contain variables intended for use in a formatted printing operation. I looked at the docs for array_map:
http://php.net/manual/en/function.array-map.php
and the user comments and I did not see any use case where the first parameter in a call to array_map() was an array itself. In all the use cases I saw, the first parameter was either NULL or a (callback) function. It seems pretty obvious to me that the code takes the $args array and then builds a new array with the arguments sanitized by $this->sql_escape_string().
But the statement "array($this, 'sql_escape_string')" is throwing me since I would have expected simply '$this->sql_escape_string', or is that not a valid syntax? If so, how does wrapping $this and 'sql_escape_string' in an array create a valid callback function for array_map() to use?
It is actually passing the sql_escape_string method from the class itself as a callback. It is a way of clarifying ambiguous method calls. For example:
array_map('sql_escape_string', $args);
of course applies sql_escape_string() to each value in $args, whereas:
array_map(array($someClass, 'sql_escape_string'), $args);
applies the sql_escape_string() method from $someClass to each value in $args.
The first parameter is a callback. It can be either a string or an array.
since I would have expected simply '$this->sql_escape_string'
You would if it were just one scalar value. But you have an array and you need to apply that escape function to each item of the $args array. So you need to implement foreach and apply that function or use one-liner with array_map.
But the statement "array($this, 'sql_escape_string')" is throwing me since I would have expected simply '$this->sql_escape_string', or is that not a valid syntax?
It's valid, but doesn't refer to what you think it refers to. Consider free functions, constants, class names and variables: each exists in different environments (or "namespaces" if you prefer, but that's easily confused with PHP namespaces). The different environment for variables is made explicit by the use of "$" as a sigil: the variable $foo versus the function foo(), constant foo and class Foo. This is also why constants and variables are case-sensitive, but functions and class names aren't: the different environments allow for different name resolution rules.
Similarly, object methods and properties exist in different environments. As a consequence, $this->sql_escape_string refers to a property, not a method. To confuse matters, that property could contain a callable, though such a callable couldn't be invoked directly:
class Foo {
function frob() {return 23.0 / 42;}
}
$foo = new Foo;
$foo->frob = function () {return 0 / 0;};
$foo->frob(); # calls method, not closure function
$frob = $foo->frob;
$frob(); # oops: division by zero
As with constants and functions, properties and methods are distinguished by the absence or presence of an argument list.
If so, how does wrapping $this and 'sql_escape_string' in an array create a valid callback function for array_map() to use?
PHP's syntax for callable references goes beyond strings.
Free functions (functions not associated with a class or object; contrast with "bound functions") can unambiguously be referred to by their names. Static methods are bound to a class, but can be referred to with a string if it includes the class name (the syntax is "Class::method"). A string cannot contain enough information for an object method, however, since the method must be bound to a particular object, and PHP doesn't have a way to refer to an object using a string. The solution PHP's developers settled on was to use array syntax (as shown in the question sample code). They also included support for array syntax for static methods (array('Class', 'method')).
Besides callable references, callables can be closures. These offer an alternative way of passing object methods, but are more verbose and complex.
$self = $this; # workaround: $this not accessible in closures before 5.4
$args = array_map(
function ($value) use($self) {
return $self->sql_escape_string($value);
}, $args);
Closures aren't so useful when a callable reference will do, but are more powerful overall.

Function to create new, previously undefined variable

Sorry for such a lame title, but I just had no idea what to put there, hope you understand it. Plus, I have no idea if similar question has been asked before, because I don't know the proper keywords for it - therefore couldn't google it too.
Basicly... When looking at preg_match_all();, they got this matches parameter that will create new array defined in function, and give us the ability to access it after function execution.
And the question is.. How can I implement such a feature in my own function? But that it could create single variable and/or array.
Thanks in advance!
preg_match_all() accepts a reference to an array, which in its own scope is called $matches. As seen in the function prototype:
array &$matches
If you call the function and pass in a variable, if it does not already exist in the calling scope it will be created. So in your user-defined function, you accept a parameter by reference using &, then work with it inside your function. Create your outer-scope variable by simply declaring it in your function call, like you the way you call preg_match_all() with $matches.
An example:
function foo(&$bar) {
$bar = 'baz';
}
// Declare a variable and pass it to foo()
foo($variable);
echo $variable; // baz
I think you are referring to function parameters passed by reference, are you not?
function putValInVar(&$myVar, $myVal){
$myVar = $myVal;
}
$myVar = 1;
putValInVar($myVar, 2);
echo $myVar; // outputs '2', but will output '1' if we remove the '&' //
By default function arguments in PHP are passed by value. This means that new variables are created at each function call and those variables will exist only inside the function, not affecting anything outside it.
To specify that an argument should be used by reference the syntax is to append an & before declaring it in the function header. This will instruct PHP to use the passed variable inside the function rather than creating a copy of it.
Exception: Objects are always passed by reference. (Well... Not really, but it's complicated. See the comment thread for more info.)
I think what you are asking for is passing-by-reference. What preg_match_all basically does to "create" an array variable outside its scope is:
function preg_match_all($foo, $bar, & $new_var) {
$new_var = array(1,2,3);
}
The crucial point here is & in the function definition. This allows you to overwrite variables in the outer scope when passed.
Stylistically this should be used with care. Try to return arrays or results instead of doing it via reference passing.
Like this:
$myvariable = runfunction();
function runfunction() {
//do some code assign result to variable (ie $result)
return $result;
}
Or
global $result;
function runfunction() {
global $result;
$result = 'something';
}

Can a PHP callback accept its parameter(s) by reference?

I've tested the following and it works on both PHP 5.2 and 5.3, however, it's not documented anywhere as far as I can see so I'm evaluating its use.
I have a function in a class called isValid, this checks a hash to see if the given value is in the set of allowed values. There are some values that are valid, but deprecated; I'd like my isValid function to update the passed in value to the current one and return true.
That's fine for when I call it myself, however, I'd like to use this method when used as a callback for array_filter too.
Here's a test case, which as expected results in an array with the values 2,3,4,5,6.
<?php
$test = array(1, 2, 3, 4, 5);
echo print_r(array_filter($test, 'maptest'), true);
function maptest(&$value)
{
$value ++;
return true;
}
So StackOverflow: is this allowed, or is it undocumented functionality that may disappear/stop working/cause errors in the future?
Yes, it's allowed.
In this respect, there's nothing special about calling functions through callbacks.
However, your specific example does not illustrate one difficulty. Consider:
function inc(&$i) { $i++; }
$n = 0;
// Warning: Parameter 1 to inc() expected to be a reference, value given:
call_user_func('inc', $n);
The problem is that you're passing $n to call_user_func and call_user_func doesn't accept values by reference. So by the time inc is called, it won't receive a reference. This isn't a problem with array_filter because it traverses the array directly and can directly pass the variables in the array to the callback function.
You could use call-time pass-by-reference, but this is deprecated and removed from trunk:
function inc(&$i) { $i++; }
$n = 0;
// Deprecated: Call-time pass-by-reference has been deprecated
call_user_func('inc', &$n);
So the best option is to use call_user_func_array instead:
function inc(&$i) { $i++; }
$n = 0;
call_user_func_array('inc', array(&$n));
This function will pass-by-reference the elements that have the is_ref flag set and will pass-by-value the other ones.
Except when explicitly noted, I'd say this is fine and acceptable. A callback can be any built-in or user-defined function.

Categories