Intereting Posts
Как хранить html в базе данных mysql cURL и fopen медленнее в браузере, быстро через командную строку Хорошая идея / плохая идея? Использование MySQL RAND () вне небольшого набора результатов подзапроса? Есть ли способ для glob () только файлов? Как преобразовать все символы в их эквивалент сущности html с помощью PHP преобразовать часть элемента dom в строку с тегами html внутри них Флажок и проверка всех функций в Datatable JQuery PHP Mysql Нужна помощь в разделении строки в переменной и присвоении ее частей массиву Почему Apache 2.1.7 в WAMP не регистрирует ошибки PHP в журнале ошибок PHP? запуск load_class на mthaml Обновить поле инкремента запроса плюс 1 codeigniter Ошибка подключения 10060 при подключении к службе push push Показать файлы PDF в браузере пользователей через PHP / Perl Работает среда Symfony2, среда prod дает ошибку 404 Автоматически обновлять токен с помощью google drive api с помощью php-скрипта

call_user_func_array передает аргументы конструктору

Я искал много страниц результатов Google, а также здесь, в stackoverflow, но не могу найти решение, которое, похоже, соответствует моей ситуации. Кажется, у меня есть одна последняя загвоздка в функции, которую я пытаюсь построить, которая использует call_user_func_array для динамического создания объектов.

Уловимая фатальная ошибка, которую я получаю, – Object of class Product could not be converted to string . Когда ошибка возникает, в журнале я получаю пять из них (по одному для каждого аргумента): PHP Warning: Missing argument 1 for Product::__construct(), перед опасной фатальной ошибкой.

Это код функции:

 public static function SelectAll($class, $table, $sort_field, $sort_order = "ASC") { /* First, the function performs a MySQL query using the provided arguments. */ $query = "SELECT * FROM " .$table. " ORDER BY " .$sort_field. " " .$sort_order; $result = mysql_query($query); /* Next, the function dynamically gathers the appropriate number and names of properties. */ $num_fields = mysql_num_fields($result); for($i=0; $i < ($num_fields); $i++) { $fetch = mysql_fetch_field($result, $i); $properties[$i] = $fetch->name; } /* Finally, the function produces and returns an array of constructed objects.*/ while($row = mysql_fetch_assoc($result)) { for($i=0; $i < ($num_fields); $i++) { $args[$i] = $row[$properties[$i]]; } $array[] = call_user_func_array (new $class, $args); } return $array; } 

Теперь, если я прокомментирую строку call_user_func_array и заменим ее следующим:

 $array[] = new $class($args[0],$args[1],$args[2],$args[3],$args[4]); 

Страница загружается так, как должна, и заполняет таблицу, которую я создаю. Итак, все абсолютно функционально, пока я не попытаюсь использовать массив $args в call_user_func_array .

Есть ли какие-то тонкие подробности о том, что я вызываю этот массив? Я читал руководство по PHP для call_user_func_array один раз, а затем некоторые, и примеры на этой странице, казалось, показывали людям просто создание массива и вызов его для второго аргумента. Что я могу делать неправильно?

Solutions Collecting From Web of "call_user_func_array передает аргументы конструктору"

Вы не можете вызвать конструктор $class следующим образом:

 call_user_func_array (new $class, $args); 

Это не действительный обратный вызов как первый параметр. Давайте выделим это отдельно:

 call_user_func_array (new $class, $args); 

Такой же как

 $obj = new $class; call_user_func_array ($obj, $args); 

Как вы можете видеть, конструктор $class уже call_user_func_array до того, как call_user_func_array вступает в действие. Поскольку у него нет параметров, вы увидите это сообщение об ошибке:

 Missing argument 1 for Product::__construct() 

Кроме того, $obj имеет тип объекта. Действительный обратный вызов должен быть либо строкой, либо массивом (или исключительно особым объектом: Closure , но это не обсуждается здесь, я назову его только для полноты).

Поскольку $obj является объектом, а не действительным обратным вызовом, вы видите сообщение об ошибке PHP:

 Object of class Product could not be converted to string. 

PHP пытается преобразовать объект в строку, который он не позволяет.

Итак, как вы можете видеть, вы не можете легко создать обратный вызов для конструктора, поскольку объект еще не существует. Возможно, именно поэтому вы не смогли легко найти это в руководстве.

Конструкторам нужна специальная работа здесь: если вам нужно передать переменные аргументы конструктору класса объекта not-yet initialize, вы можете использовать ReflectionClass для этого:

  $ref = new ReflectionClass($class); $new = $ref->newInstanceArgs($args); 

См. ReflectionClass::newInstanceArgs

Невозможно использовать call_user_func_array() , потому что (как следует из названия) он вызывает функции / методы, но не предназначен для создания объектов, Use ReflectionClass

 $refClass = new ReflectionClass($class); $object = $refClass->newInstanceArgs($args); 

Другое (более основанное на дизайне) решение представляет собой статический заводский метод

 class MyClass () { public static function create ($args) { return new self($args[0],$args[1],$args[2],$args[3],$args[4]); } } 

а затем просто

 $object = $class::create($args); 

В моих глазах это чище, потому что меньше магии и большего контроля

Я использую это для шаблона фабрики singleton, потому что ReflectionClass ломает дерево зависимостей, я ненавижу использование eval, но это единственный способ найти упрощение использования шаблона singleton для ввода mockObjects с PHPUnit без открытия методов класса для этой инъекции , БУДЬТЕ ОСТОРОЖНЫ, ЧЕМ ДАННЫЕ, ЧТО ВЫ ПРОХОДИТЕ В ФУНКЦИЮ eval !!!!!!!! ВЫ ДОЛЖНЫ БЫТЬ УВЕРЕНЫ, ЧТО ОЧИСТНО И ФИЛЬТРИРОВАНО !!!

 abstract class Singleton{ private static $instance=array();//collection of singleton objects instances protected function __construct(){}//to allow call to extended constructor only from dependence tree private function __clone(){}//to disallow duplicate private function __wakeup(){}//comment this if you want to mock the object whith php unit jejeje //AND HERE WE GO!!! public static function getInstance(){ $a=get_called_class(); if(!array_key_exists($a, self::$instance)){ if(func_num_args()){ /**HERE IS THE CODE **// $args=func_get_args(); $str='self::$instance[$a]=new $a('; for($i=0;$i<count($args);$i++){ $str.=(($i)?",":"").'$args['.$i.']'; } eval($str.");");//DANGER, BE CAREFULLY...we only use this code to inject MockObjects in testing...to another use you will use a normal method to configure the SingletonObject /*--------------------------*/ }else{ self::$instance[$a]=new $a(); } } return self::$instance[$a]; } } 

И использовать это:

 class MyClass extends Singleton{ protected function __construct(MyDependInjection $injection){ //here i use the args like a normal class but the method IS PROTECTED!!! } } 

для стимулирования объекта:

 $myVar= MyClass::getInstance($objetFromClassMyDependInjection); 

он вызывает конструктор с аргументами, которые я поставил. я знаю, что я могу получить тот же результат, расширяющий статический метод getInstance, но для совместной работы его более простой в использовании таким образом