Как безопасно и динамически создать экземпляр существующего класса PHP?

Скажем, у меня есть файл Foo.php:

<?php
interface ICommand
{
     function doSomething();
}

class Foo implements ICommand
{
    public function doSomething()
    {
        return "I'm Foo output";
    }
}

?>

Если я хочу создать класс типа Foo, я мог бы использовать:

require_once("path/to/Foo.php") ;
$bar = new Foo(); 

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

register("Foo", "path/to/Foo.php");

function register($className, $classPath)
{
    require_once($classPath); //Error if the file isn't included, but lets 
                              //assume that the file "Foo.php" exists.
    $classInstance = new $className; //What happens here if the class Foo isn't 
                                     //defined in the file "Foo.php"? 

    $classInstance->doSomething(); //And what happens here if this code is executed at
                                   //all?
    //Etc...
}

Как мне убедиться, что эти классы действительно находятся там, где они указаны в файле конфигурации? А что произойдет, если класса нет (но есть файл), создаст ли он экземпляр динамически сгенерированного класса, не имеющий дальнейшего описания?


person Timo    schedule 06.09.2010    source источник


Ответы (2)


Вы можете использовать class_exists, чтобы проверить, определен ли класс.

Если вы вызываете класс динамически, а также вызываете метод этого класса из той же функции, вы также можете захотеть вызвать этот метод динамически (если только все ваши классы не имеют одного и того же метода. В этом случае вы можете также используйте method_exists

Наконец, вы также можете использовать file_exists, чтобы убедиться, что файл можно включить :

register("Foo", "path/to/Foo.php", "bar", array('arg1', 'arg2'));

function register($className, $classPath, $methodName, $args)
{
    if(!file_exists($classPath)) return false;

    require_once($classPath);

    if(!class_exists($className)) return false;

    $classInstance = new $className;

    if(!method_exists($classInstance, $methodName)) return false;

    $classInstance->$methodName($args);
}
person Rupert Madden-Abbott    schedule 06.09.2010
comment
На самом деле, все мои классы имеют один и тот же метод (все они реализуют интерфейс, который я описал в начале моего вопроса), но тем не менее, это хорошая идея, чтобы действительно выполнить эту проверку, поскольку можно позже добавят новые реализации. - person Timo; 06.09.2010

Если вы попытаетесь создать экземпляр класса, который не определен, например

$o = new IsNotDefined();

вызывается автозагрузчик, и в качестве параметра передается имя класса. Если зарегистрированный автозагрузчик предоставляет реализацию класса, сценарий продолжается «нормально». Если реализация класса не может быть предоставлена, php останавливается на Fatal error: Class 'IsNotDefined' not found.

Вас также может заинтересовать

person VolkerK    schedule 06.09.2010
comment
Спасибо за ответ! Я прочитал документацию __autoloader, и то, что вы говорите, верно для версий ниже 5.3 (с которыми, естественно, я работаю (например, 5.2), поэтому для меня никаких исключений;)) К сожалению, в моем распоряжении есть поведение по умолчанию, поэтому фатальный ошибка недопустима. - person Timo; 06.09.2010