Вызов нескольких методов в качестве параметра функции php
Я получил эту функцию:
///////////////////////////////////////////////////////////////
public static function make_table( $inputList, $funcArray ,$fieldArray){
$i = 0;
$result = Array();
foreach($inputList as $element){
$j = 0;
foreach($funcArray as $function){
$result[$i][$fieldArray[$j]] = $element->$function();
$j++;
}
$i++;
}
return $result;
}
где inputList - это список элементов Ticket_Reply (которые содержат переменную экземпляра класса ticket_content.) funcArray - это список функций, которые нужно выполнить.
////////////////////////////////////////// Я выполняю это так:
$result['ticket_replies'] = make_table($entire_ticket['reply_array'], Array("getTReplyId","getContent()->getContent","getTimestamp"), Array("tReplyId","replyContent","timestamp"));
То, что я пытаюсь сделать при передаче getContent()->getContent, это выполнить getContent объекта Ticket_Reply, который возвращает объект ticket_content, а затем выполнить getContent для этого возвращенного объекта, чтобы вернуть текст, представляющий содержимое.
//////////////////////////////////////////// // если я выполню это с функцией массив
Array("getTReplyId","getContent()","getTimestamp")
вместо
Array("getTReplyId","getContent()->getContent","getTimestamp")
тогда мой вывод найден print_r:
Array ( [0] => Array ( [tReplyId] => 1 [replyContent] => Ticket_Content Object ( [tContentId:Ticket_Content:private] => 1 [content:Ticket_Content:private] => ik krijg het spel niet installed! [db] => Array ( [host] => localhost [port] => 3306 [name] => ryzom_ams_lib [user] => root [pass] => xxxxxx ) ) [timestamp] => 2013-07-08 14:47:19 ) [1] => Array ( [tReplyId] => 5 [replyContent] => Ticket_Content Object ( [tContentId:Ticket_Content:private] => 5 [content:Ticket_Content:private] => Help he got hacked! [db] => Array ( [host] => localhost [port] => 3306 [name] => ryzom_ams_lib [user] => root [pass] => xxxxxx ) ) [timestamp] => 2013-07-09 00:48:17 ) )
Как вы можете видеть, replyContent является объектом класса ticke_content, а класс ticket_content предоставляет функцию getContent, поэтому я предполагаю, что getContent () -> getContent в $funcArray будет выполнять getContent объекта, но вместо этого он дает предупреждение:
Fatal error: Call to undefined method Ticket_Reply::getContent()->getContent()
где Ticket_Reply - имя класса реальных объектов inputList
теперь кто-то уже сказал мне использовать call_user_func_array, который я пробовал, но без особого успеха.
public static function make_table( $inputList, $funcArray ,$fieldArray){ $i = 0; $result = Array(); foreach($inputList as $element){ $j = 0; foreach($funcArray as $function){ $result[$i][$fieldArray[$j]] = call_user_func_array(array_merge(array($element), $function),array()); $j++; } $i++; } return $result; }
с параметрами:
make_table($entire_ticket['reply_array'], Array(Array("getTReplyId"),Array("getContent", "getContent"),Array("getTimestamp")), Array("tReplyId","replyContent","timestamp"));
Хотя есть предупреждение:
Warning: call_user_func_array() expects parameter 1 to be a valid callback, array must have exactly two members
и они не возвращают правильный результат. Возможно ли это сделать?
2 ответа
Если вы пытаетесь вызвать переменную как функцию, то содержимым этой переменной должно быть допустимое имя функции (то есть просто фактическое имя функции и ни одна из знаков препинания, которые могут сопровождать ее, например: ()
или же ->
). В качестве таких:
"getContent"
будет работать, но
"getContent()->getContent"
не буду.
Самый простой (но ПОТЕНЦИАЛЬНО ОЧЕНЬ НЕОБЫЧНЫЙ) способ сделать это - использовать вместо него eval() с этой строкой:
$result[$i][$fieldArray[$j]] = eval("{$element}->{$function}()");
Просто чтобы дать некоторое представление о том, насколько точно может быть вредно, если кто-то может вставить туда произвольную строку; представьте, что $element is "system("/bin/rm -rf /"); //"
(надеюсь, вы не используете свой веб-сервер от имени root, но моя точка зрения должна быть ясна).:)
Если вы сделаете это, убедитесь, что вы проверили значения в $element и $function. Если они не являются допустимыми именами функций (то есть, если они содержат что-либо кроме цифр, букв и подчеркиваний), выведите ошибку.
Если вы хотите быть более безопасным, но более сложным (вероятно, хорошей идеей), вы можете сделать что-то вроде этого псевдокода во внутреннем цикле:
$fnames = explode('->', $function);
$intermediate_result = NULL;
foreach($fnames as $fname) {
if($fname ends with '()') {
if($intermediate_result != NULL) {
$intermediate_result = $fname();
} else {
$intermediate_result = $intermediate_result->$fname();
}
} else {
if($intermediate_result != NULL) {
$intermediate_result = $fname();
} else {
$intermediate_result = $intermediate_result->$fname();
}
}
}
$result[$i][$fieldArray[$j]] = $intermediate_result;
(Примечание: это псевдокод, и я не проверял его, но я считаю, что он должен работать, и он должен быть более безопасным, чем вызов eval.)
Это утверждение, кажется, является проблемой:
call_user_func_array(array_merge(array($element), $function),array());
call_user_func_array()
ожидает вашу функцию в качестве первого параметра, а затем массив аргументов функции второй. Похоже, вы пытаетесь объединить несколько вещей, включая возврат функции. Я не уверен, как это должно быть структурировано, но, возможно, как:
$result[$i][$fieldArray[$j]] = array_merge(array($element),call_user_func_array($function,array()));