PHP может выполнить волшебное инстанцирование?

Учитывая класс 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];
    }
}

5
задан Sebastián Grignoli 28 May 2017 в 17:31
поделиться

10 ответов

Я не уверен, что это именно то, что вы ищете, но это идея. Код должен быть понятным.

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.

2
ответ дан 14 December 2019 в 01:03
поделиться

Возможно, я неправильно интерпретирую вашу проблему, но если вам нужен один экземпляр класса для использования во всем приложении (например, класс базы данных), я бы предложил вам использовать паттерн фабрики. Тогда в любой момент, когда вам понадобится класс, вы сможете сделать что-то вроде.....

$obj = &MyFactory::getClass('mysql_database_class');

Я бы определенно исключил инстанцирование классов в конце файлов классов. Если вы пытаетесь следовать стандартным принципам ООП, то вы должны избегать этого любой ценой, так как это может привести к коллизиям в других частях вашего кода.

2
ответ дан 14 December 2019 в 01:03
поделиться

call_user_func_array (array ($ className, '__ construct'), $ args);

1
ответ дан 14 December 2019 в 01:03
поделиться

делает ли это то, что вы хотите?

class CommonAppBase {}
class RandomName extends CommonAppBase {}
$klass = 'RandomName';
$instance = new $klass();
1
ответ дан 14 December 2019 в 01:03
поделиться

Я думаю, вам всегда будет нужен 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`
1
ответ дан 14 December 2019 в 01:03
поделиться

Моя попытка, которая делает то, что мне нужно (сомнительно)

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();
    }
}
1
ответ дан 14 December 2019 в 01:03
поделиться

Предполагая, что у вас есть __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');
1
ответ дан 14 December 2019 в 01:03
поделиться

В качестве компьютерного эксперимента вы можете использовать функцию APD override_function , чтобы переопределить функцию include .

В новой функции вы можете разметить включенный файл (для получения определений классов) и создать экземпляр при обнаружении класса.

0
ответ дан 14 December 2019 в 01:03
поделиться
  1. сопоставить каждый URL-адрес с index.php
  2. найти файл из $ _ SERVER ['REQUEST_URI'] (или что-то еще работает для вас)
  3. используйте переменное имя класса для инициализации ( $ main = new $ file () )

MVC-фреймворки обычно делают что-то вроде этого, но более структурированным способом:

  1. запрос перенаправляется через mod_rewrite на index.php, который загружает и запускает своего рода диспетчер
  2. , диспетчер анализирует URL-адрес: http://example.com/foo/bar/baz превращается в ] $ controller = 'foo', $ action = 'bar', $ param = 'baz'
  3. диспетчер включает controllers / foo.php
  4. , а затем создает его экземпляр: $ controllerInstance = new $ controller ()
  5. затем вызывает действие и передает ему параметр: call_user_func_array (array ($ controllerInstance, 'do'.ucfirst ($ action)), array ($ param))
0
ответ дан 14 December 2019 в 01:03
поделиться

Вы рассмотрели возможность использования Reflection для динамического создания классов?

$cls = new ReflectionClass('ClassName');
$obj = $cls->newInstance();

Вы также можете получить его родительский класс.

0
ответ дан 14 December 2019 в 01:03
поделиться
Другие вопросы по тегам:

Похожие вопросы: