PHP 5.4 Pass-by-time-by-reference - Solution facile disponible?

219

Existe-t-il un moyen de résoudre facilement ce problème ou ai-je vraiment besoin de réécrire tout le code hérité?

PHP Fatal error: Call-time pass-by-reference a été supprimé dans ... sur la ligne 30

Cela se produit partout car les variables sont passées dans les fonctions comme références dans le code.

bardiir
la source

Réponses:

344

Vous devez désigner l'appel par référence dans la définition de la fonction, pas l'appel réel. Depuis que PHP a commencé à afficher les erreurs de dépréciation dans la version 5.3, je dirais que ce serait une bonne idée de réécrire le code.

De la documentation :

Il n'y a pas de signe de référence sur un appel de fonction - uniquement sur les définitions de fonction. Les définitions de fonction suffisent à elles seules pour passer correctement l'argument par référence. Depuis PHP 5.3.0, vous obtiendrez un avertissement vous indiquant que "call-time pass-by-reference" est déconseillé lorsque vous utilisez &dans foo(&$a);.

Par exemple, au lieu d'utiliser:

// Wrong way!
myFunc(&$arg);               # Deprecated pass-by-reference argument
function myFunc($arg) { }

Utilisation:

// Right way!
myFunc($var);                # pass-by-value argument
function myFunc(&$arg) { }
Tim Cooper
la source
9
La dépréciation est depuis PHP 5.0.0, en arrière ce temps donnant une E_COMPILE_WARNINGerreur de niveau, pour référence: php.net/manual/en/…
hakre
5
J'ai eu cette erreur mais j'ai dû supprimer le & insted d'ajouter à la variable.
Diana
2
Je l'avais utilisé dans l'ancien code pour un objet appelé événement (& $ event), et j'ai dû supprimer l'esperluette pour que le message d'erreur disparaisse.
Natalia
1
dans toutes mes années en tant que développeur, je n'ai en fait jamais eu besoin d'utiliser & sur php. plus jamais. c'était exactement ce que je cherchais. grand
Juan Vilar
8
pour les personnes dans les commentaires, notez que la suppression du & peut entraîner des résultats inattendus car toute modification de la variable ne sera plus partagée mais ne sera visible que pour l'étendue locale des fonctions. Donc, à moins que vous ne sachiez ce que fait le code, je recommanderais de le corriger comme décrit ci-dessus au lieu de simplement supprimer le caractère &
xorinzor
8

Pour tous ceux qui, comme moi, lisent ceci parce qu'ils ont besoin de mettre à jour un projet hérité géant vers la version 5.6: comme le soulignent les réponses ici, il n'y a pas de solution rapide: vous avez vraiment besoin de trouver chaque occurrence du problème manuellement et de le corriger .

Le moyen le plus pratique que j'ai trouvé pour trouver toutes les lignes problématiques dans un projet (à moins d'utiliser un analyseur de code statique complet, qui est très précis mais je n'en connais aucun qui vous amène immédiatement à la bonne position dans l'éditeur) utilisait Visual Studio Code, qui a un joli linter PHP intégré, et sa fonction de recherche qui permet une recherche par Regex. (Bien sûr, vous pouvez utiliser n'importe quel éditeur IDE / Code pour cela qui effectue des recherches PHP linting et Regex.)

En utilisant cette expression régulière:

^(?!.*function).*(\&\$)

il est possible de rechercher dans tout le projet la présence de &$ uniquement dans les lignes qui ne sont pas une définition de fonction.

Cela se révèle encore beaucoup de faux positifs, mais cela rend le travail plus facile.

Le navigateur de résultats de recherche de VSCode facilite la navigation et la recherche des lignes incriminées: il vous suffit de cliquer sur chaque résultat et de rechercher celles que le linter souligne en rouge. Ceux que vous devez réparer.

Pekka
la source
1
C'est ce que je cherchais!
Sonny
4
Regex plus précis que j'utilise à cette fin:(?<!function)[:> ][a-zA-Z0-9_]+(?<!foreach|array)\s?\([^()]*&\$
Mojo
utilisez simplement phpcs, déterrera chaque fichier qui a ceci pour vous.
Thomas Cheng
6

PHP et les références ne sont pas intuitives. Si elles sont utilisées correctement, les références aux bons endroits peuvent améliorer considérablement les performances ou éviter des solutions de contournement très laides et un code inhabituel.

Ce qui suit produira une erreur:

 function f(&$v){$v = true;}
 f(&$v);

 function f($v){$v = true;}
 f(&$v);

Aucun de ceux-ci ne doit échouer car ils pourraient suivre les règles ci-dessous mais ont sans aucun doute été supprimés ou désactivés pour éviter beaucoup de confusion héritée.

S'ils ont fonctionné, les deux impliquent une conversion redondante en référence et la seconde implique également une conversion redondante en une variable contenue de portée.

Le second était auparavant possible, permettant de passer une référence à du code qui n'était pas destiné à fonctionner avec des références. C'est extrêmement moche pour la maintenabilité.

Cela ne fera rien:

 function f($v){$v = true;}
 $r = &$v;
 f($r);

Plus précisément, il transforme la référence en une variable normale car vous n'avez pas demandé de référence.

Cela fonctionnera:

 function f(&$v){$v = true;}
 f($v);

Cela montre que vous passez une non-référence mais que vous voulez une référence, la transforme donc en référence.

Cela signifie que vous ne pouvez pas passer une référence à une fonction où une référence n'est pas explicitement demandée pour en faire l'un des rares domaines où PHP est strict sur les types de passage ou dans ce cas plus d'un type méta.

Si vous avez besoin d'un comportement plus dynamique, cela fonctionnera:

 function f(&$v){$v = true;}
 $v = array(false,false,false);
 $r = &$v[1];
 f($r);

Ici, il voit que vous voulez une référence et que vous avez déjà une référence, alors laissez-le tranquille. Il peut également enchaîner la référence mais j'en doute.

jgmjgm
la source