Попытка понять странный вариант вызова PHP array_map()
Я пытаюсь понять некоторый код, который я нашел в библиотеке oauth-php с открытым исходным кодом. Соответствующий фрагмент кода:
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);
}
Где $args - это массив аргументов, которые содержат переменные, предназначенные для использования в операции форматированной печати. Я посмотрел на документы для array_map:
http://php.net/manual/en/function.array-map.php
и комментарии пользователей, и я не видел ни одного варианта использования, где первым параметром в вызове array_map() был сам массив. Во всех случаях использования, которые я видел, первым параметром была либо NULL, либо функция (обратного вызова). Мне кажется довольно очевидным, что код принимает массив $args, а затем создает новый массив с аргументами, очищенными с помощью $this->sql_escape_string().
Но утверждение "массив ($this, 'sql_escape_string')" бросает меня, поскольку я ожидал бы просто "$ this-> sql_escape_string", или это неверный синтаксис? Если это так, как перенос $ this и 'sql_escape_string' в массив создает действительную функцию обратного вызова для использования array_map()?
- росшлер
3 ответа
Это на самом деле прохождение sql_escape_string
Метод из самого класса в качестве обратного вызова. Это способ выяснения неоднозначных вызовов методов. Например:
array_map('sql_escape_string', $args);
конечно относится sql_escape_string()
к каждому значению в $args
, в то время как:
array_map(array($someClass, 'sql_escape_string'), $args);
применяет sql_escape_string()
метод из$someClass
к каждому значению в $args
,
Первый параметр - это обратный вызов. Это может быть либо строка, либо массив.
так как я ожидал бы просто '$this->sql_escape_string'
Вы бы, если бы это было только одно скалярное значение. Но у вас есть массив, и вам нужно применить эту escape-функцию к каждому элементу $args
массив. Так что вам нужно реализовать foreach
и применить эту функцию или использовать одну строку с array_map
,
Но утверждение "массив ($this, 'sql_escape_string')" бросает меня, поскольку я ожидал бы просто "$this->sql_escape_string", или это неверный синтаксис?
Это действительно, но не относится к тому, что вы думаете, это относится. Рассмотрим свободные функции, константы, имена классов и переменные: каждая существует в разных средах (или "пространствах имен", если вы предпочитаете, но это легко спутать с пространствами имен PHP). Другое окружение для переменных становится явным с помощью "$" в качестве сигилы: переменная $foo
по сравнению с функцией foo()
постоянная foo
и класс Foo
, Именно поэтому константы и переменные чувствительны к регистру, а функции и имена классов - нет: разные среды допускают разные правила разрешения имен.
Точно так же методы и свойства объекта существуют в разных средах. Как следствие, $this->sql_escape_string
относится к свойству, а не к методу. Чтобы запутать вещи, это свойство может содержать вызываемый объект, хотя такой вызываемый объект не может быть вызван напрямую:
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
Как и в случае констант и функций, свойства и методы отличаются отсутствием или наличием списка аргументов.
Если это так, как перенос $ this и 'sql_escape_string' в массив создает действительную функцию обратного вызова для использования array_map()?
Синтаксис PHP для вызываемых ссылок выходит за рамки строк.
Свободные функции (функции, не связанные с классом или объектом; в отличие от "связанных функций") могут однозначно именоваться их именами. Статические методы связаны с классом, но на них можно ссылаться строкой, если она включает имя класса (синтаксис "Class::method"). Однако строка не может содержать достаточно информации для метода объекта, поскольку метод должен быть привязан к определенному объекту, а в PHP нет способа ссылаться на объект с помощью строки. Решением, на котором остановились разработчики PHP, было использование синтаксиса массива (как показано в примере кода вопроса). Они также включили поддержку синтаксиса массива для статических методов (array('Class', 'method')
).
Помимо вызываемых ссылок, вызываемые могут быть замыканиями. Они предлагают альтернативный способ передачи объектных методов, но являются более подробными и сложными.
$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);
Замыкания не так полезны, когда подойдёт вызываемая ссылка, но в целом более эффективны.