7.4+:
Хорошая новость, что это будет реализовано в новых выпусках, как отметил @Andrea. Я просто оставлю это решение здесь на случай, если кто-то захочет использовать его до 7.4.
7.3 или меньше
Основываясь на уведомлениях, которые я до сих пор получаю из этой ветки, я считаю, что у многих людей была та же проблема, что и у меня. Моим решением для этого случая было объединение сеттеров + __set
магический метод внутри трейта для имитации этого поведения. Вот:
trait SettersTrait
{
public function __set($name, $value)
{
$setter = 'set'.$name;
if (method_exists($this, $setter)) {
$this->$setter($value);
} else {
$this->$name = $value;
}
}
}
А вот и демонстрация:
class Bar {}
class NotBar {}
class Foo
{
use SettersTrait;
private $bar;
protected function setBar(Bar $bar)
{
$this->bar = $bar;
}
}
$foo = new Foo();
$foo->bar = new NotBar();
Объяснение
Прежде всего, определите bar
как частное свойство, чтобы PHP __set
выполнял автоматическое преобразование .
__set
проверит, объявлен ли какой-нибудь сеттер в текущем объекте ( method_exists($this, $setter)
). В противном случае он установит только свое значение, как обычно.
Объявите метод установки (setBar), который получает аргумент с подсказкой типа ( setBar(Bar $bar)
).
Пока PHP обнаруживает, что что-то, что не является Bar
экземпляром, передается сеттеру, он автоматически запускает фатальную ошибку: Uncaught TypeError: аргумент 1, переданный в Foo :: setBar (), должен быть экземпляром Bar, экземпляр NotBar задан