[Résolu] Comportement bizarre d'une fonction entre PHP5 et PHP8

Comportement bizarre d'une fonction entre PHP5 et PHP8 [Résolu] - PHP - Programmation

Marsh Posté le 23-11-2023 à 16:50:38    

Bonjour,
Je suis tombé sur bug provenant d'une différence entre PHP5 et PHP8 dans l'ajout d'un élément dans un tableau que je ne m'explique pas  :pt1cable:  
 

Code :
  1. function Toto($aTableau)
  2. {
  3.     $iNbPoints = count($aTableau);
  4.     if ($aTableau[0] != $aTableau[$iNbPoints - 1])
  5.     {
  6.         $aTableau[] = $aTableau[0];
  7.         $iNbPoints++;
  8.     }
  9.     print_r($aTableau);
  10.     ...
  11. }


 
$aTableau est un array.
 
Mettons que $aTableau contienne 20 éléments, ils sont donc numérotés dans mon tableau de 0 à 19. Si je passe dans mon test, je vais ajouter un élément à l'indice 20 du coup. En PHP5, c'est bien le cas. En PHP8, bizarrement, mon élément ajouté l'est mais à l'indice 21. Et j'ai pas d'indice 20.  :pt1cable:  
Obligé de faire $aTableau = array_values($aTableau) dans le test après l'ajout de l'élément pour renuméroter de 0 à 20 mes éléments. Je pige pas pourquoi : première fois que je vois ça.
 
Une idée ?
 
Merci :)
 
Edit : ajouter l'élément via array_push() provoque le même comportement. :/


Message édité par rufo le 24-11-2023 à 17:12:54

---------------
Astres, outil de help-desk GPL : http://sourceforge.net/projects/astres, ICARE, gestion de conf : http://sourceforge.net/projects/icare, Outil Planeta Calandreta : https://framalibre.org/content/planeta-calandreta
Reply

Marsh Posté le 23-11-2023 à 16:50:38   

Reply

Marsh Posté le 23-11-2023 à 17:52:49    

Lu,
 
parce que $aTableau contient déjà des trous à la base ? (indices non contigus)
 
Tu utilises unset avant ?

Reply

Marsh Posté le 23-11-2023 à 20:07:47    

Non, si je fais un print_r($aTableau) avant mon if, j'ai bien mes éléments numérotés de 0 à 19.
Le print_r($aTableau) après le test montre les éléments numérotés de 0 à 19 + le 21, sans n° 20... quand je suis en PHP8. En PHP5, j'ai un comportement normal :/


---------------
Astres, outil de help-desk GPL : http://sourceforge.net/projects/astres, ICARE, gestion de conf : http://sourceforge.net/projects/icare, Outil Planeta Calandreta : https://framalibre.org/content/planeta-calandreta
Reply

Marsh Posté le 24-11-2023 à 07:55:26    

Et si tu fais un var_dump($iNbPoints, $aTableau); entre la ligne 3 et 4 (avant le if et la modification des données), tu as exactement le même output en php 5 et en 8 ?


---------------
D3
Reply

Marsh Posté le 24-11-2023 à 09:00:34    

Tu dois avoir quelque-chose quelque-part avant qui modifie le tableau, ce qui a pour conséquence l'avancement de l'indice du nouvel élément.
 
Par exemple, si on fait un unset sur le dernier élément :

Code :
  1. $aTableau = array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
  2. unset( $aTableau[9] );
  3. Toto($aTableau);


 

Code :
  1. Array
  2. (
  3.     [0] => 0
  4.     [1] => 1
  5.     [2] => 2
  6.     [3] => 3
  7.     [4] => 4
  8.     [5] => 5
  9.     [6] => 6
  10.     [7] => 7
  11.     [8] => 8
  12.     [10] => 0
  13. )


 
On voit bien le trou, c'est un comportement normal. Avec unset, ça a toujours été le cas.
 
Donc le problème est ailleurs : tu dois avoir quelque-chose qui modifie le tableau bien avant, mais dont le comportement a changé entre PHP5 & PHP8. Ça a même pu arriver avec PHP7.

Reply

Marsh Posté le 24-11-2023 à 10:50:53    

mechkurt a écrit :

Et si tu fais un var_dump($iNbPoints, $aTableau); entre la ligne 3 et 4 (avant le if et la modification des données), tu as exactement le même output en php 5 et en 8 ?


Oui.


---------------
Astres, outil de help-desk GPL : http://sourceforge.net/projects/astres, ICARE, gestion de conf : http://sourceforge.net/projects/icare, Outil Planeta Calandreta : https://framalibre.org/content/planeta-calandreta
Reply

Marsh Posté le 24-11-2023 à 10:58:40    

FlorentG a écrit :

Tu dois avoir quelque-chose quelque-part avant qui modifie le tableau, ce qui a pour conséquence l'avancement de l'indice du nouvel élément.
 
Par exemple, si on fait un unset sur le dernier élément :

Code :
  1. $aTableau = array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
  2. unset( $aTableau[9] );
  3. Toto($aTableau);


 

Code :
  1. Array
  2. (
  3.     [0] => 0
  4.     [1] => 1
  5.     [2] => 2
  6.     [3] => 3
  7.     [4] => 4
  8.     [5] => 5
  9.     [6] => 6
  10.     [7] => 7
  11.     [8] => 8
  12.     [10] => 0
  13. )


 
On voit bien le trou, c'est un comportement normal. Avec unset, ça a toujours été le cas.
 
Donc le problème est ailleurs : tu dois avoir quelque-chose qui modifie le tableau bien avant, mais dont le comportement a changé entre PHP5 & PHP8. Ça a même pu arriver avec PHP7.


 
J'ai tout à fait pensé à ça, le coup du unset. Le truc, c'est que mon tableau est passé en paramètre de la fonction, donc, pour moi, c'est par recopie (à moins qu'en PHP8, le passage par défaut serait par référence, mais je ne crois pas).
Et surtout, un print_r($aTableau) avant mon if affiche bien le tableau avec les indices de 0 à 19.
 
Précision, mais je ne pense pas que ça ait une importance. Mon tableau a une forme un peut plus complexe : ses valeurs sont en fait des array associatifs avec 2 valeurs (latitude et longitude)

Code :
  1. function Toto($aTableau)
  2.     {
  3.         $iNbPoints = count($aTableau);
  4.         if (($aTableau[0]['lat'] != $aTableau[$iNbPoints - 1]['lat']) || ($aTableau[0]['lng'] != $aTableau[$iNbPoints - 1]['lng']))
  5.         {
  6.             $aTableau[] = array('lat' => $aTableau[0]['lat'], 'lng' => $aTableau[0]['lng']);
  7.             $iNbPoints++;
  8.         }
  9.         print_r($aTableau);
  10.         ...
  11.     }


---------------
Astres, outil de help-desk GPL : http://sourceforge.net/projects/astres, ICARE, gestion de conf : http://sourceforge.net/projects/icare, Outil Planeta Calandreta : https://framalibre.org/content/planeta-calandreta
Reply

Marsh Posté le 24-11-2023 à 10:58:48    

En y réfléchissant, si les indices doivent être garantis successifs, tu devrais dans tous les cas mettre un array_values. Là tu as trouvé un bug potentiel (qui devrait être couvert par un test unitaire par la suite). Si quelqu'un appel ta fonction avec un array foireux, ton code ne retourne pas quelque-chose de correct. Vaux mieux la jouer safe.

Reply

Marsh Posté le 24-11-2023 à 11:06:58    

C'est bon, j'ai trouvé !
 
Ca venait bien d'un unset mais fait avant l'appel à ma fonction.
 
En gros, j'avais un truc du genre :

Code :
  1. $iNb = count($MonTableau);
  2.     unset($MonTableau[$iNb - 1]);
  3.     $Resultat = Toto($MonTableau);
  4.     function Toto($aTableau)
  5.     {
  6.         $iNbPoints = count($aTableau);
  7.         if ($aTableau[0] != $aTableau[$iNbPoints - 1])
  8.         {
  9.             $aTableau[] = $aTableau[0];
  10.             $iNbPoints++;
  11.         }
  12.         print_r($aTableau);
  13.         ...
  14.     }


 
Vu que la variable $MonTableau est passée par recopie à ma fonction, pour moi, le paramètre $aTableau n'avait pas connaissance de l'indice précédemment effacé par unset() hors de la fonction alors que si :/


Message édité par rufo le 24-11-2023 à 11:10:36

---------------
Astres, outil de help-desk GPL : http://sourceforge.net/projects/astres, ICARE, gestion de conf : http://sourceforge.net/projects/icare, Outil Planeta Calandreta : https://framalibre.org/content/planeta-calandreta
Reply

Marsh Posté le 24-11-2023 à 11:08:24    

Met-nous la raison, si un pauvre hère cherche dans 20 ans, et tombe sur ce topic :o

Reply

Marsh Posté le 24-11-2023 à 11:08:24   

Reply

Marsh Posté le 24-11-2023 à 11:11:54    

Du reste, manifestement, en PHP5, $aTableau n'a effectivement pas connaissance de l'indice précédemment effacé hors de la fonction alors qu'en PHP8, il ne a connaissance. En tout cas, c'est la conclusion à laquelle j'arrive.


Message édité par rufo le 24-11-2023 à 14:40:49

---------------
Astres, outil de help-desk GPL : http://sourceforge.net/projects/astres, ICARE, gestion de conf : http://sourceforge.net/projects/icare, Outil Planeta Calandreta : https://framalibre.org/content/planeta-calandreta
Reply

Marsh Posté le 24-11-2023 à 14:39:38    

Tu peux éventuellement remplacer unset :

Code :
  1. unset($MonTableau[$iNb - 1]);


Par array_splice :

Code :
  1. array_splice($MonTableau, $iNb - 1, 1);

Reply

Marsh Posté le 24-11-2023 à 15:07:38    

Oui, pourquoi pas. Ca va renuméroter les clés de 0 à n.
Mais la conclusion est qu'il y a bien une différence de comportement entre PHP5 et PHP8 concernant la suppression du dernier élément d'un tableau.
L'un va mettre le nouvel élément ajouté au premier indice libre alors que l'autre va le mettre après l'indice de l'élément supprimé. C'est pas intuitif comme comportement je trouve et très piégeux :/


---------------
Astres, outil de help-desk GPL : http://sourceforge.net/projects/astres, ICARE, gestion de conf : http://sourceforge.net/projects/icare, Outil Planeta Calandreta : https://framalibre.org/content/planeta-calandreta
Reply

Marsh Posté le 24-11-2023 à 15:12:49    

À mon avis y'a autre chose encore. Parce qu'en testant sur une 5.6 ou une 8.2, j'ai le même comportement [:johneh] Est-ce que ton tableau est trimballé ailleurs entre le unset, et l'appel à la fonction ?

Reply

Marsh Posté le 24-11-2023 à 15:15:21    

https://www.php.net/manual/fr/function.unset.php
En lisant la doc, vers le bas, je suis tombé sur ce commentaire :  
"Be careful!, unset() element in array advances the internal array pointer one place forward"
 
Mais c'est pas précisé depuis quelle version on a ce comportement.


---------------
Astres, outil de help-desk GPL : http://sourceforge.net/projects/astres, ICARE, gestion de conf : http://sourceforge.net/projects/icare, Outil Planeta Calandreta : https://framalibre.org/content/planeta-calandreta
Reply

Marsh Posté le 24-11-2023 à 15:16:27    

FlorentG a écrit :

À mon avis y'a autre chose encore. Parce qu'en testant sur une 5.6 ou une 8.2, j'ai le même comportement [:johneh] Est-ce que ton tableau est trimballé ailleurs entre le unset, et l'appel à la fonction ?


Non.
Ma version est du PHP8.0.10 et du PHP5.4.31.
 
Edit : ce matin, j'ai fais des tests dans tous les sens. Si j'enlève le unset() fait sur mon tableau avant d'être passé en paramètre à ma fonction, tout va bien. J'utilise un uWamp. Donc, pour faire mon test, j'ai juste à changer la version de PHP dans une liste déroulante. Ben je vois bien la différence de comportement. Du reste, j'ai fait le même test sur un PHP7.4.33. J'observe le même comportement qu'en PHP8.0.10.


Message édité par rufo le 24-11-2023 à 15:21:02

---------------
Astres, outil de help-desk GPL : http://sourceforge.net/projects/astres, ICARE, gestion de conf : http://sourceforge.net/projects/icare, Outil Planeta Calandreta : https://framalibre.org/content/planeta-calandreta
Reply

Marsh Posté le 24-11-2023 à 16:49:43    

Ah oui du 5.4 ! C'est peut-être entre la 5.4 et la 5.6. On va finir pas trouver :D

Reply

Marsh Posté le 24-11-2023 à 17:14:54    

J'ai mis en résolu mon topic car j'ai compris ce qui se passait et la doc de PHP concernant unset() semble bien mentionner ce comportement.
 
Mais perso, je regrette le comportement plus logique à mon sens de PHP5.4. T'enlèves le dernier élément, tu t'attends franchement à ce que le nouveau empilé prenne l'indice suivant et pas en sauter un. Et le comportement ne devrait pas dépendre de comment tu as enlevé le dernier élément :/


---------------
Astres, outil de help-desk GPL : http://sourceforge.net/projects/astres, ICARE, gestion de conf : http://sourceforge.net/projects/icare, Outil Planeta Calandreta : https://framalibre.org/content/planeta-calandreta
Reply

Marsh Posté le 25-11-2023 à 10:15:32    

Est-ce que t'as regardé du coté de https://www.php.net/manual/en/function.array-pop.php ?


---------------
Un cycle complet sera une série de 100.
Reply

Marsh Posté le 25-11-2023 à 10:25:00    

Oui, cette fonction n'aurait pas causé le pb. Mais c'est bien ce que je dis : c'est pas normal que suivant la manière dont on enlève le dernier élément, le comportement diffère sur le positionnement de l'index. Un coup, ça le réinitialise, un coup non :/


---------------
Astres, outil de help-desk GPL : http://sourceforge.net/projects/astres, ICARE, gestion de conf : http://sourceforge.net/projects/icare, Outil Planeta Calandreta : https://framalibre.org/content/planeta-calandreta
Reply

Marsh Posté le 25-11-2023 à 10:40:35    

Les gars, la première fois que j'ai fait du PHP y a 20 ans, l'ado que j'étais s'est dit "quel bordel ce langage, c'est plein de failles potentielles et de comportements chelous, je ne comprends pas que ça soit utilisé par des millions de sites et pas juste des pages persos de bidouilleurs du dimanche sans qu'internet s'effondre toutes les semaines".
Bah là quand je vous lis je me dis que c'est toujours pareil, sauf que maintenant je suis vieux :o

 

Je ne comprends pas qu'un langage puisse altérer entre deux versions le comportement d'un truc utilisé depuis 70 ans comme les tableaux, c'est pas vraiment un truc expérimental :pt1cable:


Message édité par TotalRecall le 25-11-2023 à 10:44:10

---------------
Réalisation amplis classe D / T      Topic .Net - C# @ Prog
Reply

Marsh Posté le 25-11-2023 à 16:07:30    

Là en l'ocurrence c'est le même merdier en JS avec la propriété length des tableaux :o

Reply

Marsh Posté le 02-12-2023 à 10:17:18    

Je me tiens le plus loin possible du JS, mais je sais que sur les chaînes ça donne des résultats rigolo dès qu'on est sur de l'UTF / Unicode (il faut utiliiser un truc bizarre avec des crochets autour de la chaîne pour avoir les "vraies" longueurs), et qu'on peut utiliser l'indexeur pour glisser des trucs après la dernière position quitte à poser quelques undefined en chemin, mais au moins j'imagine que ça s'est toujours comporté pareil... Non ? ... Non :fouyaya: ? Ca a changé de comportement length en js au fil des années ? [:totoz]


Message édité par TotalRecall le 02-12-2023 à 10:17:33

---------------
Réalisation amplis classe D / T      Topic .Net - C# @ Prog
Reply

Marsh Posté le 02-12-2023 à 11:50:03    

Je sais pas, je suis resté en ISO-8859-1 :o


---------------
Astres, outil de help-desk GPL : http://sourceforge.net/projects/astres, ICARE, gestion de conf : http://sourceforge.net/projects/icare, Outil Planeta Calandreta : https://framalibre.org/content/planeta-calandreta
Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed