46 votes

Comment "[" peut être un opérateur dans la spécification du langage PHP?

Sur la page http://php.net/manual/fr/language.operators.precedence.php, le deuxième niveau de précédence le plus élevé contient un opérateur à associativité gauche appelé [.

Je n'ai pas compris cela. Est-ce que le [ est utilisé pour accéder / modifier les entrées de tableau, comme dans $myArray[23] ? Je ne peux pas imaginer un extrait de code où nous aurions besoin de connaître la "précédence" par rapport aux autres opérateurs, ou où l '"associativité" de [ serait utile.

67voto

trincot Points 10112

C'est une question très valable.

1. Précédence entre [...]

Tout d'abord, il n'y a jamais d'ambiguïté quant à ce que PHP doit évaluer en premier en regardant le côté droit du [, car le crochet nécessite un crochet de fermeture pour l'accompagner, et donc chaque opérateur entre a priorité sur le crochet ouvrant.

Exemple:

$a[1+2]

Le + a priorité, c'est-à-dire que d'abord 1+2 doit être évalué avant que PHP puisse déterminer quel élément récupérer de $a.

Mais la liste de priorité des opérateurs ne concerne pas cela.

2. Associativité

Deuxièmement, il y a un ordre d'évaluation des paires consécutives de [], comme ici:

$b[1][2]

PHP évaluera d'abord $b[1] puis appliquera [2] à cela. C'est une évaluation de gauche à droite et c'est ce qui est prévu avec une associativité à gauche.

Mais la question en jeu n'est pas tellement sur l'associativité, mais sur la priorité par rapport à d'autres opérateurs.

3. Précédence sur les opérateurs du côté gauche

La liste indique que les opérateurs clone et new ont priorité sur [, et ce n'est pas facile à tester.

Tout d'abord, la plupart des structures où vous combineriez new avec des crochets sont considérées comme une syntaxe invalide syntaxe. Par exemple, l'une de ces déclarations:

$a = new myClass()[0];
$a = new myClass[0];

donnera une erreur d'analyse:

erreur de syntaxe, '[' inattendu

PHP vous oblige à ajouter des parenthèses pour rendre la syntaxe valide. Nous ne pouvons donc pas tester les règles de priorité de cette manière.

Mais il y a une autre façon, en utilisant une variable contenant un nom de classe:

$a = new $test[0];

Cette syntaxe est valide, mais maintenant le défi est de créer une classe qui crée quelque chose qui agit comme un tableau.

Ce n'est pas trivial à faire, car une propriété d'objet est référencée de cette manière: obj->prop, et non comme obj["prop"]. On peut cependant utiliser la classe ArrayObject class qui peut gérer les crochets. L'idée est d'étendre cette classe et redéfinir la méthode offsetGet method pour s'assurer qu'un objet fraîchement créé de cette classe a des éléments de tableau à retourner.

Pour rendre les objets imprimables, j'ai fini par utiliser la méthode magique __toString, qui est exécutée lorsque l'objet doit être converti en chaîne.

J'ai donc mis en place ce système, en définissant deux classes similaires:

class T extends ArrayObject {
    public function __toString() {
        return "Je suis un objet T";
    } 
    public function offsetGet ($offset)  {
        return "Je suis un élément de tableau d'un objet T";
    }
}

class TestClass extends ArrayObject {
    public function __toString() {
        return "Je suis un objet de la classe TestClass";
    } 
    public function offsetGet ($offset)  {
        return "Je suis un élément de tableau d'un objet de la classe TestClass";
    }
}

$test = "TestClass";

Avec cette configuration, nous pouvons tester quelques choses.

Test 1

echo new $test;

Cette déclaration crée une nouvelle instance de TestClass, qui doit ensuite être convertie en chaîne, donc la méthode __toString est appelée sur cette nouvelle instance, ce qui renvoie:

Je suis un objet de la classe TestClass

C'est ce qu'on attend.

Test 2

echo (new $test)[0];

Ici, nous commençons par les mêmes actions, car les parenthèses forcent l'exécution de l'opération new en premier. Cette fois, PHP ne convertit pas l'objet créé en chaîne, mais demande l'élément du tableau 0. Cette demande est répondue par la méthode offsetGet, et donc la déclaration ci-dessus affiche:

Je suis un élément de tableau d'un objet de la classe TestClass

Test 3

echo new ($test[0]);

L'idée est de forcer l'ordre d'exécution inverse. Malheureusement, PHP n'autorise pas cette syntaxe, nous devrons donc diviser la déclaration en deux afin d'obtenir l'ordre d'évaluation souhaité:

$name = $test[0];
echo new $name;

Alors maintenant, le [ est exécuté en premier, prenant le premier caractère de la valeur de $test, c'est-à-dire "T", et ensuite new est appliqué à cela. C'est pourquoi j'ai aussi défini une classe T. L'appel de echo à __toString sur cette instance, ce qui donne:

Je suis un objet T

Arrive maintenant le test final pour voir quel est l'ordre lorsqu'il n'y a pas de parenthèses:

Test 4

echo new $test[0];

Cette syntaxe est valide, et...

4. Conclusion

La sortie est:

Je suis un objet T

En fait, PHP a appliqué le [ avant l'opérateur new, contrairement à ce qui est indiqué dans le tableau de priorités des opérateurs!

5. Comparaison de clone avec new

L'opérateur clone a un comportement similaire en combinaison avec [. Étrangement, clone et new ne sont pas complètement égaux en termes de règles de syntaxe. Reproduire le test 2 avec clone:

echo (clone $test)[0];

renvoie une erreur d'analyse:

erreur de syntaxe, '[' inattendu

Mais le test 4 répété avec clone montre que [ a priorité sur lui.

@bishop a informé que cela reproduit le bug de documentation de longue date #61513: "La précédence de l'opérateur clone est incorrecte".

5voto

Maks3w Points 3377

Cela signifie simplement que la variable du tableau (associativité à gauche - $first) sera évaluée avant la clé du tableau (associativité à droite - $second)

$first[$second]

Cela a beaucoup de sens lorsque le tableau a plusieurs dimensions

$first[$second][$third][$fourth]

4voto

Xorifelse Points 1726

En PHP, vous pouvez initialiser des tableaux vides avec [] donc pour savoir comment définir un tableau, la priorité du caractère suivant détermine comment initialiser le tableau.

Comme les tableaux font partie de la structure de syntaxe, cela se fait avant toute opération mathématique, ayant simplement une priorité plus élevée que les autres opérateurs de calcul pour cette raison.

var_dump([5, 6, 7] + [1, 2, 3, 4]); # 5674 - Les tableaux doivent être connus avant d'appliquer l'opérateur

Cependant, pour être honnête, je ne comprends pas vraiment la question. Dans la plupart des langages de programmation, les [ et les ] sont associés aux tableaux qui font partie de la syntaxe de base et ont toujours une priorité élevée (si ce n'est la plus élevée).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X