【问题标题】:How to make an exception to "private" constructors?如何对“私有”构造函数进行例外处理?
【发布时间】:2019-05-18 14:00:45
【问题描述】:

我想声明一个非公共构造函数,因此该类的用户不能直接调用new Message(),而是必须从Message 扩展的抽象类上声明的静态构建器方法实例化对象。

到目前为止,我的代码是:

abstract class SqlDecodable  {
    public function instanceFromRawSql (array $rawSql) {
        $newInstanceToReturn = new static() // problem is here 
        // .. map the new instance .. 
        return $newInstance ;
    } 

}

// for exemple... 
class Message extends SqlDecodable {
    private $receiverId ; 
    private $senderId ; 
    private $text ;

    private/protected/public?? function __construct() {
        // problem here : this constructor should be usable only by 
           parent class, not for user of Message
    }
    static function propertiesToSqlFields() {
        return [
        "receiverId" => "receiver_id_field_in_db", 
        "senderId" => "sender_id",
        "text" => "text" 
        ]
    }
}

这个其实比较复杂,不过我为这个问题简化了系统

当我实现我的方法instanceFromRawSqlArray时,我必须创建一个子类的新实例:$instanceToReturn = new static(),然后一个一个地设置变量。

尽管如此,我不想让 __construct 在我的模型类中不接受任何参数。我不希望 Message 的开发用户能够new Message()

这个构造函数应该只能被instanceFromRawSqlArray 使用。 问题是,正如我所见,PHP 中没有 C++ 朋友类。我不能让我的 __construct 受保护,因为正如我所见,受保护的方法对孩子来说是可访问的,而不是对父母来说。

您是否有想法在方法 instanceFromRawSqlArray 中映射这个新实例,而不创建任何会破坏我的模型类“封装保护”的构造函数或设置器?

【问题讨论】:

    标签: php oop friend


    【解决方案1】:

    你们很亲密。您可以简单地将您的构造函数声明为protected

    直接实例化类是行不通的,但是你可以从抽象类中声明的静态方法中调用new

    例如:

    abstract class SuperAbstract {
    
        static function create() {
            return new static();
        }
    }
    
    class Extended extends SuperAbstract {
    
        private $hello = '';
    
        protected function __construct() {
            $this->hello = "world";
        }
    
        public function hello() {
            return "hello " . $this->hello;
        }
    }
    
    // works
    $a = Extended::create();
    
    echo $a->hello(); // outputs "hello world"
    
    // can't touch this. This will fail because the constructor is `protected`.
    $b = new Extended();
    

    当然,因为它是protected,所以也可以从子类中调用构造函数。这是不可避免的,只要有子类是可能的。但是您也可以将Extended 声明为final,从而无法扩展类。因此,只能从抽象父级中定义的工厂方法创建新实例。

    final Extended extends SuperAbstract
    
        protected function __construct() { }
    }
    

    您可以在此处看到它工作(和失败):https://3v4l.org/LliKj

    【讨论】:

    • 感谢您的回答,它有效! :) 我不知道受保护的方法也可以从父母那里访问(以为只有孩子可以访问它们)
    • stackoverflow.com/q/56338792/8631622 请调查这个问题。我做了我能做的一切。但我无法解决这个问题@yivi
    猜你喜欢
    • 2012-07-13
    • 2018-11-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-08
    • 1970-01-01
    • 2020-12-03
    相关资源
    最近更新 更多