开发者

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 sni开发者_开发技巧ppet 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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜