Вызов нескольких методов в качестве параметра функции 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()));
Другие вопросы по тегам