父母公开时,如何使子构造函数私有?

时间:2018-12-20 13:41:39

标签: php class oop inheritance constructor

为什么无法在子类中隐藏构造函数?

我收到以下异常:

  

致命错误:必须访问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 :(得分:3)

您可以使用继承来扩展方法的可见性。以下示例是正确的

class A
{
   private function __construct()
   {}
}

class B extends A
{

   public function __construct()
   {}
}

但是您不能在子类中限制方法的可见性。以下示例不正确

class A
{
   public function __construct()
   {}
}

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

在您的情况下,由于要创建单例,因此尝试隐藏构造函数。在很多情况下,单例都是不好的做法。你应该用 对象构建的其他模式:Static FactoryService LocatorDependency Injection Container

例如,您可以通过简单修改static工厂来存档必要的结果:

class LoggerFactory
{
    private static $instance = null;

    public static function build()
    {
        if (is_null(static::$instance)) { 
            static::$instance = // making of the logger
        }
        return static:$instance;
    }
}

答案 1 :(得分:1)

实际上没有任何方法可以强制子类接受比您要覆盖的父函数更低级别的visibility

您可能想要的是一个包装类,它模仿父类但不extend

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);
    }
}

答案 2 :(得分:1)

您不能使子类方法(在这种情况下是构造函数,但应用相同的原理)比父类更具限制性。因为将使用该 type 的客户端代码期望具有与超类相同的协定/接口。否则,您不能透明地将超类的实例替换为您的类的实例,反之亦然。

但是,您的超类依赖于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
}