Как сделать исключение для «частных» конструкторов? - PullRequest
2 голосов
/ 18 мая 2019

Я хочу объявить непубличный конструктор, чтобы его пользователи класса не могли напрямую вызывать 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, без создания какого-либо конструктора или установщика, которые повредили бы мой класс модели "защита от инкапсуляции"?

1 Ответ

2 голосов
/ 19 мая 2019

Вы были очень близки.Вы можете просто объявить ваш конструктор как 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();

OfКонечно, поскольку это protected, конструктор также может вызываться из дочерних классов.Это неизбежно, до тех пор, пока возможны детские классы .Но вы также можете объявить Extended как final, что сделает расширение класса невозможным.Таким образом, было бы возможно создать новые экземпляры только из фабричного метода, определенного в абстрактном родительском объекте.

final Extended extends SuperAbstract

    protected function __construct() { }
}

Вы можете увидеть, как он работает (и не работает), здесь: https://3v4l.org/LliKj

...