Заставить динамически загружаемый класс расширять или реализовывать интерфейс

Кто-нибудь знает, возможно ли в PHP заставить класс расширять или реализовывать интерфейс без его объявления дочерним классом?

Пример:

interface Requirements
{
    public function __construct();
    public function kittens();
}

class DingleBerry
{
    public function __construct()
    {
        // yadda yadda yadda    
    }
}

// Example of my initial hope
// of what you could do

$kittens = new DingleBerry implements Requirements;

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

Моя общая цель — проверить, реализует ли класс требования ДО его загрузки и вызова его конструктора.

Поэтому я НЕ МОГУ использовать это:

interface Requirements
{
    public function __construct();
    public function kittens();
}

class DingleBerry
{
    public function __construct()
    {
        // DO BAD STUFF (i.e. eat your soul)
    }
}

// Example of what I CANNOT
// do.

$kittens = new DingleBerry;

if( !($kittens instanceof Requirements) )
{
    // eat pizza.    
}

Потому что конструктор DingleBerry вызывается до того, как я могу проверить, реализует ли он требования. Копать землю?


person Jay    schedule 26.01.2011    source источник


Ответы (2)


Вы не можете изменить уже объявленный класс или определение интерфейса без использования стороннего расширения (например: runkit).

В Runkit есть функция runkit_class_adopt, которая может удовлетворить эту потребность. К сожалению, я не могу протестировать его, потому что версия PECL не скомпилируется на моей машине.

В первой части вашего вопроса вы можете проверить, реализует ли класс данный интерфейс без его создания и без API-интерфейса Reflection:

// checks if class Bar implements Foo
if (in_array('Foo', class_implements('Bar'))) {
    $foo = new Bar;
} else {
    throw new Exception('Interface not implemented');
}
person netcoder    schedule 27.01.2011
comment
Обратите внимание, что class_implements попытается автоматически загрузить класс, если вы не передадите false в качестве второго параметра, как это делает class_exists. - person Synchro; 29.07.2013

Непроверенный, но теоретически это API:

<?php
$reflection = new ReflectionClass('DingleBerry');
$reflection->implementsInterface('Requirements');
?>

http://php.net/manual/en/book.reflection.php
http://mark-story.com/posts/view/using-the-php-reflection-api-for-fun-and-profit

person scragz    schedule 26.01.2011
comment
Это проверит, реализован ли интерфейс, но не заставит класс реализовать его. - person netcoder; 27.01.2011
comment
Ах, ну, это ко второй части вашего вопроса о том, что конструктор DingleBerry вызывается до того, как вы сможете проверить, реализует ли он это. - person scragz; 27.01.2011
comment
Похоже, вам придется переписать его на Ruby! - person scragz; 27.01.2011
comment
Если я не могу заставить это, это определенно следующая лучшая вещь. Спасибо, скрагз, молодец. (Минус вашего комментария Ruby) Я отредактировал его на ReflectionsClass => ReflectionClass, т.е. удалил 's' - person Jay; 27.01.2011