Hace php 7 de apoyo, tipo de sugerencias para las propiedades de la clase?

Me refiero, no sólo para incubadoras/getters pero para la misma propiedad.

Algo como:

class Foo {
    /**
     *
     * @var Bar
     */
    public $bar : Bar;
}

$fooInstance = new Foo();
$fooInstance->bar = new NotBar(); //Error
  • No que yo sepa. Sin embargo, en general se habla de ningún tipo de restricciones en el valor de una propiedad deben realizarse a través de un setter de todos modos. Desde el setter puede tener fácilmente un typehint por el «valor» del argumento, usted es bueno ir.
  • Muchos marcos por ahí hace uso de atributos protegidos (sobre todo para los controladores). Para aquellos casos en particular, sería muy útil.

4 Comentarios

  1. 120

    PHP 7.4 apoyará escribió propiedades así:

    class Person
    {
        public string $name;
        public DateTimeImmutable $dateOfBirth;
    }

    PHP 7.3 y versiones anteriores no son compatibles con este, pero hay algunas alternativas.

    Puede hacer que una propiedad privada, que es accesible sólo a través de getters y setters que han declaraciones de tipo:

    class Person
    {
        private $name;
        public function getName(): string {
            return $this->name;
        }
        public function setName(string $newName) {
            $this->name = $newName;
        }
    }

    Usted también puede hacer un público de la propiedad y el uso de un bloque de documentación para proporcionar el tipo de información a la gente que lee el código y el uso de un IDE, pero esto no proporciona ningún tipo en tiempo de ejecución-verificación:

    class Person
    {
        /**
          * @var string
          */
        public $name;
    }

    Y, de hecho, se pueden combinar los getters y los setters y un bloque de documentación.

    Si eres más aventurero, usted podría hacer un fake de la propiedad con el __get, __set, __isset y __unset la magia de los métodos de, y de verificación de los tipos a ti mismo. No estoy seguro de si yo la recomendaría, aunque.

    • Suena realmente bien. No puedo esperar a ver cuál es el que viene en las próximas versiones!
    • Ugh. La vergüenza de que el RFC no se pudo 🙁
    • ¿Hay alguna explicación de por qué este RFC fue rechazado?
    • Es una mierda, sabiendo que la propuesta es rechazada.
    • Hay una oportunidad para que este RFC para ser examinada de nuevo en el futuro? (Especialmente si los problemas de rendimiento son mitigados.) Ganó el 60% de la mayoría de 34 a 23, casi el 66% necesario. wiki.php.net/rfc/typed-properties
    • Otra cuestión importante es el manejo de referencias, que realmente no interactúan bien con el tipo de declaraciones y podría tener que ser deshabilitado para este tipo de propiedades. Incluso sin los problemas de rendimiento, no ser capaz de hacer, decir, array_push($this->foo, $bar) o sort($this->foobar) sería una gran cosa.
    • Hay un nuevo RFC en las obras wiki.php.net/rfc/typed_properties_v2
    • Escrito Propiedades de destino versión de PHP se ha cambiado de 7.3 a 7.4 y la votación se iniciará en los próximos días
    • Fue aceptado para el 7.4 hace un tiempo así que he actualizado a esta respuesta.
    • Gran noticia! Gracias por la actualización
    • ¿Cómo será la coerción de tipos de trabajo? Por ejemplo: (new Person())->dateOfBirth = '2001-01-01';… Siempre declare(strict_types=0); que es. Va a tirar o usar el DateTimeImmutable constructor? Y si ese es el caso, que tipo de error se produce si la cadena es una fecha no válida? TypeError?
    • No existe una conversión implícita a DateTime(Inmutable) y nunca ha sido

  2. 8

    7.4+:

    Buena noticia de que será implementado en las nuevas versiones, como @Andrea señaló.
    Voy a dejar esta solución aquí en caso de que alguien quiera usarlo antes de 7.4


    7.3 o menos

    Basadas en las notificaciones me sigue recibiendo de este hilo, creo que mucha gente ahí fuera que tenía/tiene el mismo problema que yo tenía. Mi solución para este caso fue la combinación de incubadoras + __set método mágico en el interior de un rasgo con el fin de 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

    Primero de todo, definir bar como una propiedad privada para PHP elenco __set automágicamente.

    __set comprobará si hay algunos setter declarado en el objeto actual (method_exists($this, $setter)). De lo contrario es sólo establecer su valor como lo haría normalmente.

    Declarar un método setter (setBar) que recibe un tipo-insinuó argumento (setBar(Bar $bar)).

    Tan largo como PHP detecta que hay algo que no es Bar instancia se pasa a la incubadora, será automáticamente desencadenar un Error Fatal: Uncaught TypeError: Argumento 1 pasa a Foo::setBar() debe ser una instancia de Bar, instancia de NotBar dado

  3. 2

    En realidad no es posible y sólo tiene 4 formas de simular :

    • Valores predeterminados
    • Decoradores en bloques de comentario
    • Valores predeterminados en el constructor
    • Getters y setters

    Me combinado de todos ellos 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;
        }
    }

    Nota de que en realidad se puede escribir la devolución ?Bar desde php 7.1 (que acepta valores null), ya que podría ser null (no disponible en php7.0.)

    También puede escribir el retorno nula desde php7.1

  4. 0

    Puede utilizar 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);

    De salida:

    TypeError: Argument 1 passed to Foo::setBar() must be an instance of Bar, instance of Foo given, called in ...

Dejar respuesta

Please enter your comment!
Please enter your name here