Как сделать дочерний конструктор приватным, когда родительский объект общедоступен? - PullRequest
0 голосов
/ 20 декабря 2018

Почему невозможно скрыть конструктор в дочернем классе?

Я получаю следующее исключение:

Неустранимая ошибка: уровень доступа к CIS \ Logger \ WPLogger :: __ construct () должен быть открытым (как в классе Katzgrau \ KLogger \ Logger)) в /builds/r2o/website/wp-content/mu-plugins/toolsets/lib/cis-logger/src/WPLogger.php в строке 12

код суперкласса (из внешней библиотеки):

    public function __construct($logDirectory, $logLevelThreshold = LogLevel::DEBUG, array $options = array()) { // ... 
    }

Код WPLogger.php (подкласс):

private function __construct(string $logDirectory, string $logLevelThreshold = LogLevel::DEBUG, array $options = array()) {
    parent::__construct($logDirectory, $logLevelThreshold, $options);
         // ... some actions
    }
}

public static function getInstance(string $logFileRelative = self::DEFAULT_LOG_NAME, string $logLevelThreshold = LogLevel::DEBUG, array $options = array()) {
       // ...
}

Я не хочу, чтобы этот специальный подкласс создавался с new.Я хочу, чтобы он создавался статически с getInstance() вместо этого по некоторым причинам.Как мне этого добиться?

Ответы [ 3 ]

0 голосов
/ 20 декабря 2018

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

Но ваш суперкласс зависит от AbstractLogger, который реализуется из Psr\Log\LoggerInterface.И поскольку я уверен , что все следуют принципу инверсии зависимостей, вы должны быть в состоянии сказать, что для WPLogger вполне нормально реализовывать непосредственно из LoggerInterface.Итак:

use Psr\Log\LoggerInterface;

final class WPLogger implements LoggerInterface
{
    private $wrapperLogger;

    private function __construct() {}

    public static function getInstance(string $logFileRelative = self::DEFAULT_LOG_NAME, string $logLevelThreshold = LogLevel::DEBUG, array $options = array()) {
       // @TODO, implement here your singleton if you want

       $self = new self();
       $self->wrapperLogger = new \Katzgrau\KLogger\Logger(...);
       return $self;
    }

    // implement the rest of the interface, delegating to wrapperLogger
}
0 голосов
/ 20 декабря 2018

Вы можете расширить видимость методов с помощью наследования.Следующий пример верен

class A
{
   private function __construct()
   {}
}

class B extends A
{

   public function __construct()
   {}
}

Но вы не можете ограничить видимость методов в детских классах.Следующий пример некорректен

class A
{
   public function __construct()
   {}
}

class B extends A
{
   private function __construct()
   {}
}

В вашем случае вы пытаетесь скрыть конструктор, потому что вы хотите создать синглтон.Синглтон - плохая практика во многих случаях.Для построения объектов следует использовать другие шаблоны: Статическая фабрика , Локатор служб , Контейнер внедрения зависимостей

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

class LoggerFactory
{
    private static $instance = null;

    public static function build()
    {
        if (is_null(static::$instance)) { 
            static::$instance = // making of the logger
        }
        return static:$instance;
    }
}
0 голосов
/ 20 декабря 2018

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

Что вам, вероятно, нужно, это класс-оболочка, который эмулирует родительский элемент, но не extend it

class Singleton {
    /** @var \Katzgrau\KLogger\Logger */
    protected $logger;
    /** @var Singleton */
    protected $instance;

    private function __construct($someargs) {
         $this->logger = new \Katzgrau\KLogger\Logger($someargs);
    }

    public static function getInstance($someargs) {
         if($this->instance instanceof Singleton) return $this->instance;
         $this->instance = new self($someargs);
         return $this->instance;
    }

    /** Magic method to pass along calls to the other class */
    function __call($method, $args) {
         call_user_func_array(array($this->logger, $method), $args);
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...