way - standard php




Digite dicas para propriedades no PHP 7? (3)

O PHP 7 suporta insinuações de tipo para propriedades de classe?

Quero dizer, não apenas para setters / getters, mas para a propriedade em si.

Algo como:

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

$fooInstance = new Foo();
$fooInstance->bar = new NotBar(); //Error

Na verdade, não é possível e você só tem 4 maneiras de simulá-lo:

  • Valores padrão
  • Decoradores em blocos de comentário
  • Valores padrão no construtor
  • Getters e setters

Eu combinei todos eles aqui

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;
    }
}

Note que você realmente pode digitar o retorno como "Bar desde php 7.1 (anulável) porque poderia ser nulo (não disponível em php7.0.)

Você também pode digitar o retorno como nulo desde php7.1


O PHP 7.4 suportará propriedades digitadas assim:

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

PHP 7.3 e anteriores não suportam isso, mas existem algumas alternativas.

Você pode criar uma propriedade privada acessível apenas por getters e setters que possuem declarações de tipo:

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

Você também pode criar uma propriedade pública e usar um bloco de documentos para fornecer informações de tipo a pessoas que leem o código e usam um IDE, mas isso não fornece verificação de tipo de tempo de execução:

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

E, de fato, você pode combinar getters e setters e um docblock.

Se você for mais aventureiro, poderá criar uma propriedade falsa com os métodos mágicos __get , __set , __isset e __unset e verificar os tipos por conta própria. Eu não tenho certeza se eu recomendo, no entanto.


7,4+:

Boas notícias de que isso será implementado nos novos lançamentos, como apontou @Andrea. Vou deixar esta solução aqui, caso alguém queira usá-la antes de 7.4

7.3 ou menos

Com base nas notificações que ainda recebo deste tópico, acredito que muitas pessoas por aí tiveram / estão tendo o mesmo problema que eu tive. Minha solução para este caso foi combinar __set mágicos setters + __set dentro de uma característica para simular este comportamento. Aqui 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;
        }
    }
}

E aqui está a demonstração:

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

Explicação

Primeiro de tudo, defina bar como uma propriedade privada, então o PHP lançará __set automagicamente .

__set irá verificar se existe algum setter declarado no objeto atual ( method_exists($this, $setter) ). Caso contrário, ele apenas definirá seu valor como normalmente faria.

Declare um método setter (setBar) que recebe um argumento de setBar(Bar $bar) tipo ( setBar(Bar $bar) ).

Contanto que o PHP detecte que algo que não é instância Bar está sendo passado para o setter, ele irá disparar automaticamente um erro fatal: UnEught TypeError: Argumento 1 passado para Foo :: setBar () deve ser uma instância de Bar, instância de NotBar dado







variable-types