Учитывая класс class RandomName extends CommonAppBase {}
есть ли любой способ автоматически создать экземпляр любого расширения класса CommonAppBase
без явного использования new
?
Как правило, только будет одно определение класса на файл PHP. И добавление new RandomName()
в конец всех файлов что-то, что я хотел бы устранить. Расширяющийся класс не имеет никакого конструктора; только CommonAppBase
конструктора вызывают. CommonAppBase->__construct()
запускает остальную часть выполнения приложений.
Странный вопрос, но было бы хорошо, если кто-либо знает решение.
В дополнение к ниже комментария. Код, который делает инстанцирование, не будет в файле класса. Файл класса будет просто, что, я хочу некоторый другой код к include('random.class.php')
и инстанцируйте любого расширения класса CommonAppBase
там.
Для любого не уверенного, что я после того, как мой ответ hackish делает то, что я хочу, но не самым нормальным способом.
Заранее спасибо, Aiden
(btw, моя версия PHP 5.3.2), заявите ограничения версии с любым ответом.
Следующее может все быть добавлено в файл (через php.ini или с Apache) к автоматическому запуску класс определенного родительского класса.
Сначала (благодарит dnagirl),
$ca = get_declared_classes();
foreach($ca as $c){
if(is_subclass_of($c, 'MyBaseClass')){
$inst = new $c();
}
}
и (принятый ответ, как самый близкий ответ)
auto_loader();
function auto_loader() {
// Get classes with parent MyBaseClass
$classes = array_filter(get_declared_classes(), function($class){
return get_parent_class($class) === 'MyBaseClass';
});
// Instantiate the first one
if (isset($classes[0])) {
$inst = new $classes[0];
}
}
Я не уверен, что это именно то, что вы ищете, но это идея. Код должен быть понятным.
auto_loader();
function auto_loader() {
// Get classes with parent MyBaseClass
$classes = array_filter(get_declared_classes(), function($class){
return get_parent_class($class) === 'MyBaseClass';
});
// Instantiate the first one
if (isset($classes[0])) {
$inst = new $classes[0];
}
}
Примечание: функции доступны с самого начала существования PHP 4, но синтаксис анонимных функций, используемый с array_filter
, был введен только в PHP 5.3.0.
Возможно, я неправильно интерпретирую вашу проблему, но если вам нужен один экземпляр класса для использования во всем приложении (например, класс базы данных), я бы предложил вам использовать паттерн фабрики. Тогда в любой момент, когда вам понадобится класс, вы сможете сделать что-то вроде.....
$obj = &MyFactory::getClass('mysql_database_class');
Я бы определенно исключил инстанцирование классов в конце файлов классов. Если вы пытаетесь следовать стандартным принципам ООП, то вы должны избегать этого любой ценой, так как это может привести к коллизиям в других частях вашего кода.
call_user_func_array (array ($ className, '__ construct'), $ args);
делает ли это то, что вы хотите?
class CommonAppBase {}
class RandomName extends CommonAppBase {}
$klass = 'RandomName';
$instance = new $klass();
Я думаю, вам всегда будет нужен new
.
Если вы хотите загрузить файл класса и инстанцировать любой класс, который там находится, я думаю, единственный действительно надежный способ - это использование get_defined_classes()
до и после включения. Любую разницу (array_diff()
) между этими двумя списками вы будете инстанцировать. Я делал это в прошлых проектах, но не стал бы делать этого сегодня из соображений элегантности и производительности.
Лучший способ IMO - быть очень строгим с именованием. Так что когда вы загружаете random.class.php
, вы определяете соглашение, что там есть один класс с именем random
, и инстанцируете его автоматически:
$classname = "random";
require "$classname.class.php";
$$classname = new $classname(); // Produces an object instance `$random`
Моя попытка, которая делает то, что мне нужно (сомнительно)
function auto_loader()
{
$file = $_SERVER['SCRIPT_FILENAME']; // Some class file
$cont = file_get_contents($file);
$tokens = token_get_all($cont);
for($i=0; $i<sizeof($tokens); $i++) {
// Token = $token[$i][0]
// Lexeme is $token[$i][1]
if($tokens[$i][0]==T_EXTENDS && $tokens[$i+2][1]=="MyBaseClass"){
// Get the lexeme of the class
$class = $tokens[$i-2][1];
break;
}
}
$inst = new $class();
}
auto_loader();
Которая автоматически добавляется через Apache или что-то еще. Вроде бы работает, но не учитывает отсутствие/изменчивость пробельных символов ($i-2
) между extends
и BaseAppClass
.
В качестве хака это, кажется, работает, немного больше кода и связывание с кэшем, и это может быть претендентом. Немного переработано.
Итак, когда запрашивается http://www.foo.com/some_class_file.php
, вышеуказанное добавляется Apache/php.ini и может инстанцировать класс в some_class_file.php
и начать его выполнение независимо от имени класса. Это происходит потому, что в моем случае URL не связан с классом. Это может быть класс MyDogBenjiClass
, который инстанцируется.
Попытка 2, спасибо dnagirl. Для запуска приложения автоматически добавляется следующее.
$ca = get_declared_classes();
foreach($ca as $c){
if(is_subclass_of($c, 'MyBaseClass')){
$inst = new $c();
}
}
Предполагая, что у вас есть __autoload
функция, в чем проблема с new
?
Но если вам нужен более косвенный метод инстанцирования, вы можете спрятать new
внутри статического метода. Итак, если ваш базовый класс имеет эти два метода:
static function make(array $args=NULL){
$class=static::who(); //note: static, NOT self
$obj=new $class($args);
//some test for whether or not $obj is acceptable
return ($test) ? $obj : false;
}
abstract static function who(){
return __CLASS__;
}
Тогда ваш объект RandomClass может попытаться инстанцироваться таким образом:
$classname= 'RandomClass';
$someargs=array(1,2,3);
if(!$newobj= $classname::make($someargs)) die('cannot make new object');
В качестве компьютерного эксперимента вы можете использовать функцию APD override_function
, чтобы переопределить функцию include
.
В новой функции вы можете разметить включенный файл (для получения определений классов) и создать экземпляр при обнаружении класса.
$ _ SERVER ['REQUEST_URI']
(или что-то еще работает для вас) $ main = new $ file ()
) MVC-фреймворки обычно делают что-то вроде этого, но более структурированным способом:
http://example.com/foo/bar/baz
превращается в ] $ controller = 'foo', $ action = 'bar', $ param = 'baz'
controllers / foo.php
$ controllerInstance = new $ controller ()
call_user_func_array (array ($ controllerInstance, 'do'.ucfirst ($ action)), array ($ param))
Вы рассмотрели возможность использования Reflection для динамического создания классов?
$cls = new ReflectionClass('ClassName');
$obj = $cls->newInstance();
Вы также можете получить его родительский класс.