Type suggérant des propriétés en PHP 7?

est-ce que php 7 supporte les types suggérant des propriétés de classe?

je veux dire, pas seulement pour setters/getters mais pour la propriété elle-même.

quelque Chose comme:

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

$fooInstance = new Foo();
$fooInstance->bar = new NotBar(); //Error
39
demandé sur Chuck Le Butt 2016-05-16 16:07:57

4 réponses

PHP 7.0, qui est la version mineure actuelle au moment de la rédaction (2016-05-16), ne supporte pas cela. Il y a eu des efforts dans cette direction (comme le propriétés dactylographiées RFC, qui a été rejeté pour PHP 7.1, mais peut être dans 7.4), mais il n'y a pas de support direct actuellement.


en attendant, il y a des alternatives.

vous pouvez faire une propriété privée qui est accessible seulement par getters et setters qui ont les déclarations de type:

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

vous pouvez également créer une propriété publique et utiliser un docblock pour fournir des informations de type aux personnes lisant le code et utilisant un IDE, mais cela ne fournit pas de vérification de type d'exécution:

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

et en effet, vous pouvez combiner getters et setters et un docblock.

si vous êtes plus aventureux, vous pourriez faire une fausse propriété avec le __get, __set,__isset et __unset méthodes magiques, et vérifiez les types vous-même. Je ne suis pas sûr si je le recommande, cependant.

55
répondu Andrea 2018-07-22 17:09:00

sur la base des notifications que je reçois encore de ce fil, je crois que beaucoup de gens là-bas avaient/ont le même problème que moi. Ma solution pour ce cas était de combiner setters+ __set méthode magique à l'intérieur d'un trait afin de simuler ce comportement. Ici, c'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;
        }
    }
}

Et voici la démonstration:

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

Explication

tout d'Abord, définir bar privé propriété donc PHP va lancer __set automatiquement.

__set va vérifier si il y a un setter déclaré dans l'objet courant (method_exists($this, $setter)). Sinon, il ne définissez sa valeur comme il le ferait normalement.

Déclarer une méthode de définition (setBar) qui reçoit un type allusion argument (setBar(Bar $bar)).

tant que PHP détecte quelque chose qui n'est pas Bar l'instance est transmise au setter, elle déclenche automatiquement une erreur fatale: Uncaught TypeError: Argument 1 passé à Toto::setBar() doit être une instance de Bar, de l'instance de NotBar donné

1
répondu CarlosCarucce 2018-07-09 05:08:55

il n'est en fait pas possible et vous n'avez que 4 façons de le simuler :

  • valeurs par Défaut
  • Décorateurs dans les blocs de commentaire
  • valeurs par Défaut dans le constructeur
  • Getters et setters

j'ai combiné tous ici

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

notez que vous pouvez taper la déclaration comme ?Depuis php 7.1 (nullable) parce qu'il pourrait être null (non disponible en php7.0.)

Vous pouvez aussi taper le retour comme nul depuis php7.1

1
répondu Bruno Guignard 2018-09-04 08:32:45
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);

Sortie:

TypeError: Argument 1 passed to Foo::setBar() must be an instance of Bar, instance of Foo given, called in ...
0
répondu Richard 2016-05-16 13:41:32