#php #oop
#php #ооп
Вопрос:
Я ищу решение о том, как использовать список аргументов для создания экземпляра класса динамически.
Например:
class test {
public function __call($name, $args){
/* blah, blah class exists? require */
return new $name($args);
}
public function __toString(){
return (string) $this->extension(); // to enforce __toString of extension
}
}
class extension extends test {
public function __construct(classTypeHint $object, $required, $random = 25){
// This does not work, results in:
// "Argument 1 passed to extension::__construct must be an instance of classTypeHint, array given...
}
public function __toString(){
return var_export($this, true);
}
}
echo new test;
Как указано в комментарии, это приводит к ошибке, но я ищу возможность доступа $object
как ( $args[0]
), $required как ( $args[1]
) и т.д. Кроме того, применяйте «правильные» аргументы.
Почему я ищу это?
__autoload
Функциональность PHP ограничена. Ну, может быть, это не так, но я не нашел простого способа дифференцировать автозагрузку классов.
С помощью этой функциональности я могу использовать __call()
, __get()
__callStatic()
для трех разных автозагрузок. Нравится:
__call()
ищет библиотеки в/includes/libraries
__get()
ищет плагины в/application/plugins
__callStatic()
ищет, ммм, кошек в/application/cats
Если есть лучший способ через автозагрузку, пожалуйста, поделитесь. Но я все еще ищу такое решение, если это возможно. Может быть, с Reflection
классами?
Несколько рабочий пример с ReflectionClass:
$instance = new ReflectionClass($name);
$instance->newInstanceArgs($arguments);
return $instance;
Но здесь очевидно, что он вызовет ReflectionClass->__toString() здесь. Кроме того, игнорируя возвращаемый дамп, он фактически не использует newInstanceArgs() здесь.
Примечания:
Меня интересует пример, работающий до PHP 5.3.
Комментарии:
1. Я думаю, вы могли бы извлечь выгоду из php.net/manual/en/function.call-user-func-array.php
2. Я не мог найти способ, как создать новый экземпляр класса с этим.
Ответ №1:
Используйте отражение:
public function __call($name, $args)
{
return (new ReflectionClass($name))->newInstanceArgs($args);
}
он принимает массив, подобный call_user_func_array
Редактировать: рабочий пример:http://codepad.org/ZZpBwRij
<?php
class MyClass
{
public function __construct($a, $b)
{
echo "__construct($a, $b) called";
}
}
function create($name, $args)
{
$class = new ReflectionClass($name);
return $class->newInstanceArgs($args);
}
var_dump(create('MyClass', array(1, 2)));
?>
Output:
__construct(1, 2) called
object(MyClass)#2 (0) {
}
Комментарии:
1. Хотя теоретически это выглядит так, у него есть 2 недостатка: 1) результаты копирования-вставки в
syntax error, unexpected T_OBJECT_OPERATOR
2) при преобразовании в несколько рабочий пример он использует__toString()
ofReflectionClass
, подчиняющийся фактическому классу__toString()
, и дает бесполезный результат.. этот неприятный дамп.2. Смотрите обновленный пост, плюс, на самом деле это не рабочий пример, потому что он не переопределяет параметры.
3. @Tom: почему очевидно, что он будет вызывать
ReflectionClass->__toString()
?
Ответ №2:
Есть лучший способ через автозагрузку.
Пространство имен вашего кода, т. Е. Создайте пространства имен «Библиотека», «Плагин» и «Кошки» в соответствующих каталогах. Например
// includes/libraries/Library/Foo.php
namespace Library;
class Foo {
// ...
}
// application/plugins/Plugin/Bar.php
namespace Plugin;
class Bar {
// ...
}
Используйте что-то вроде универсального загрузчика классов Symfony
require_once 'path/to/Symfony/Component/ClassLoader/UniversalClassLoader.php';
$loader = new SymfonyComponentClassLoaderUniversalClassLoader;
$loader->registerNamespaces(array(
'Library' => 'path/to/includes/libraries',
'Plugin' => 'path/to/application/plugins'
));
$loader->register();
$foo = new LibraryFoo;
$bar = new PluginBar;
Комментарии:
1. Была идея о
namespaces
, но есть проблема — нет пространств имен до версии 5.3. А общедоступные хосты здесь, в Латвии, в основном5.2
, и я сомневаюсь, что они обновятся в ближайшем будущем. И это на самом деле чертовски хакерское решение, которое они получили.
Ответ №3:
Итак, рабочий пример, полученный из ответа @Dani.
public function __call($name, $args){
$reflection = new ReflectionClass($name);
return $reflection->newInstanceArgs($args);
}
Работает как шарм, за исключением того, что я пока понятия не имею о производительности.