¿PHP 7 admite sugerencias de tipo para propiedades de clase?
Quiero decir, no solo para setters / getters sino para la propiedad en sí.
Algo como:
class Foo {
/**
*
* @var Bar
*/
public $bar : Bar;
}
$fooInstance = new Foo();
$fooInstance->bar = new NotBar(); //Error
php
attributes
php-7
type-hinting
variable-types
CarlosCarucce
fuente
fuente
Respuestas:
PHP 7.4 admitirá propiedades escritas así:
class Person { public string $name; public DateTimeImmutable $dateOfBirth; }
PHP 7.3 y versiones anteriores no lo admiten, pero existen algunas alternativas.
Puede crear una propiedad privada a la que solo se pueda acceder a través de getters y setters que tengan declaraciones de tipo:
class Person { private $name; public function getName(): string { return $this->name; } public function setName(string $newName) { $this->name = $newName; } }
También puede hacer una propiedad pública y usar un docblock para proporcionar información de tipo a las personas que leen el código y usan un IDE, pero esto no proporciona verificación de tipo en tiempo de ejecución:
class Person { /** * @var string */ public $name; }
Y, de hecho, puede combinar getters y setters y un docblock.
Si usted es más aventurero, puede hacer que una propiedad falso con los
__get
,__set
,__isset
y__unset
mágicos métodos , y comprobar los tipos de sí mismo. Sin embargo, no estoy seguro de si lo recomendaría.fuente
array_push($this->foo, $bar)
osort($this->foobar)
sería un gran problema.(new Person())->dateOfBirth = '2001-01-01';
... Siempredeclare(strict_types=0);
que sea así. ¿Lanzará o usará elDateTimeImmutable
constructor? Y si ese es el caso, ¿qué tipo de error se producirá si la cadena es una fecha no válida?TypeError
?7.4+:
Buenas noticias que se implementará en los nuevos lanzamientos, como señaló @Andrea. Dejaré esta solución aquí en caso de que alguien quiera usarla antes de 7.4
7.3 o menos
Según las notificaciones que todavía recibo de este hilo, creo que muchas personas han tenido el mismo problema que yo. Mi solución para este caso fue combinar setters +
__set
método mágico dentro de un rasgo para simular este comportamiento. Aquí está:trait SettersTrait { /** * @param $name * @param $value */ public function __set($name, $value) { $setter = 'set'.$name; if (method_exists($this, $setter)) { $this->$setter($value); } else { $this->$name = $value; } } }
Y aquí está la demostración:
class Bar {} class NotBar {} class Foo { use SettersTrait; //It could be implemented within this class but I used it as a trait for more flexibility /** * * @var Bar */ private $bar; /** * @param Bar $bar */ protected function setBar(Bar $bar) { //(optional) Protected so it wont be called directly by external 'entities' $this->bar = $bar; } } $foo = new Foo(); $foo->bar = new NotBar(); //Error //$foo->bar = new Bar(); //Success
Explicación
En primer lugar, defina
bar
como una propiedad privada para que PHP se__set
transmita automáticamente .__set
comprobará si hay algún setter declarado en el objeto actual (method_exists($this, $setter)
). De lo contrario, solo establecerá su valor como lo haría normalmente.Declare un método de establecimiento (setBar) que recibe un argumento con sugerencia de tipo (
setBar(Bar $bar)
).Siempre que PHP detecte que
Bar
se está pasando algo que no es una instancia al establecedor, se activará automáticamente un Error fatal: Error de tipo no detectado: El argumento 1 pasado a Foo :: setBar () debe ser una instancia de Bar, instancia de NotBar dadafuente
Editar para PHP 7.4:
Desde PHP 7.4 puede escribir atributos ( Documentación / Wiki ), lo que significa que puede hacer:
class Foo { protected ?Bar $bar; public int $id; ... }
Según wiki, todos los valores aceptables son:
PHP <7.4
En realidad, no es posible y solo tiene 4 formas de simularlo:
Los combiné todos aquí
class Foo { /** * @var Bar */ protected $bar = null; /** * Foo constructor * @param Bar $bar **/ public function __construct(Bar $bar = null){ $this->bar = $bar; } /** * @return Bar */ public function getBar() : ?Bar{ return $this->bar; } /** * @param Bar $bar */ public function setBar(Bar $bar) { $this->bar = $bar; } }
Tenga en cuenta que en realidad puede escribir el retorno como? Bar desde php 7.1 (anulable) porque podría ser nulo (no disponible en php7.0).
También puede escribir el retorno como vacío desde php7.1
fuente
Puedes usar setter
class Bar { public $val; } class Foo { /** * * @var Bar */ private $bar; /** * @return Bar */ public function getBar() { return $this->bar; } /** * @param Bar $bar */ public function setBar(Bar $bar) { $this->bar = $bar; } } $fooInstance = new Foo(); // $fooInstance->bar = new NotBar(); //Error $fooInstance->setBar($fooInstance);
Salida:
TypeError: Argument 1 passed to Foo::setBar() must be an instance of Bar, instance of Foo given, called in ...
fuente