Подтвердить что ты не робот

Расширение абстрактного одноэлементного класса

Если у вас есть класс factory, который создает какие-то новые объекты, и этот factroy-класс является singleton, например:

class Database_Factory extends Base_Factory {
    private static $factory;
    private $objects = array();

    public function __get($profile) {
        // check for object and return it if it created before
    }

    public static function getInstance(){
        if (!self::$factory)
            self::$factory = new self();
        return self::$factory;
    }
}

Тот же код повторяется в любое время, когда какой-то объект нуждается в нем factory. Поэтому я решил сделать этот абстракцию класса factory и реализовать только определенные процедуры для каждого factory. Но PHP не позволяет создавать экземпляр абстрактного класса.

abstract class Base_Factory {
    public static function getInstance(){
        if (!self::$factory)
            self::$factory = new self();
        return self::$factory;
    }
}

Неустранимая ошибка: невозможно создать абстрактный класс Base_Factory

Что бы вы сделали?

4b9b3361

Ответ 1

В методах PHP self всегда ссылается на класс, где определяется метод. Начиная с версии 5.3.0, PHP поддерживает "позднюю статическую привязку", где вы можете использовать ключевое слово static для доступа к переопределенным статическим методам, а также функцию get_called_class(), чтобы получить имя производного класса в статическом контексте.

Однако ваш дизайн имеет главный недостаток: статическое свойство $factory, определенное в Base_Factory, является общим для всех производных классов. Поэтому при первом создании и сохранении этого элемента в этом свойстве все остальные вызовы getInstance() будут возвращать один и тот же объект, независимо от того, какой производный класс используется.

Вы можете использовать статические имена классов сопоставления словаря для одиночных объектов:

abstract class Base_Factory {
    private static $_instances = array();
    public static function getInstance() {
        $class = get_called_class();
        if (!isset(self::$_instances[$class])) {
            self::$_instances[$class] = new $class();
        }
        return self::$_instances[$class];
    }
}

О, еще одна вещь. Тот факт, что вы ищете возможность повторного использования кода для одноэлементных объектов, может быть следствием того, что вы используете один шаблон дизайна singleton! Спросите себя, действительно ли классы, которые вы планируете реализовать как синглеты, - это синглтоны, и если не будет случая использования, где вы можете захотеть иметь несколько экземпляров определенного класса.

Часто гораздо лучше использовать только один синглтон, представляющий текущий "контекст приложения", который предоставляет аксессуар для объектов, которые являются одноточечными по отношению к этому контексту.

Ответ 2

PHP 5.3 +

abstract class Singleton
{
    /**
     * Instance
     *
     * @var Singleton
     */
    protected static $_instance;

    /**
     * Constructor
     *
     * @return void
     */
    protected function __construct() {}

    /**
     * Get instance
     *
     * @return Singleton
     */
    public final static function getInstance() {
        if (null === static::$_instance) {
            static::$_instance = new static();
        }

        return static::$_instance;
    }
}

Ответ 3

PHP >= 5.3 только

abstract class Base_Factory {
    protected static $factory;
    public static function getInstance(){
        if (!self::$factory) {
            $class = get_called_class();
            self::$factory = new $class();
        }
        return self::$factory;
    }
}

Ответ 4

Зарегистрируйте свои синглтоны в простом классе, таком как

class Singletons {
    static private $singleton = array();
    public function getSingleton($class) {
    if (!isset(self::$singleton[$class])) {
        self::$singleton[$class] = new $class;
    }
    return self::$singleton[$class];
    }
}

Тогда сделайте это

class aSingleton {
    public $i;
    public function test() {
    ++$this->i;
    echo get_class() . " called {$this->i} times\n";
    }
}

Singletons::getSingleton('aSingleton')->test();
Singletons::getSingleton('aSingleton')->test();

Выход

aSingleton called 1 times
aSingleton called 2 times

Ответ 5

По определению абстрактная classess не может быть создана на PHP как любые другие объектно-ориентированные языки. Таким образом, ваш Base_Factory должен быть интерфейсом вместо абстрактного класса.

Из руководства PHP: "Невозможно создать экземпляр класса, который был определен как абстрактный".

Ответ 6

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

if(__CLASS__!='Base_Factory')

Затем используйте $this вместо self, чтобы ссылаться на текущий объект вместо текущего класса.

if (!$this->factory)
        $this->factory = new self();
    return $this->factory;