8768 sujets

Développement web côté serveur, CMS

Bonjour,

Je pose la question en ayant quasiment la certitude que vous avez déjà été confrontés à ce problème :

Comment incrémenter puis décrémenter une valeur sur une boucle php foreach() toutes les 6 itérations ?

Concrètement ici je cherche a ajouter une classe offset à mes commentaires, puis

J'ai produit un code qui fonctionne mais pas forcément très joli :
	$i = -1; // Permet de passer la première itération
	foreach ( $commentsArray as $e ) {
		$i++;
		if ($i < 1)
			$offset = ''; // Pas de classe offset sur la première itération
		if ($i >= 1 AND $i < 7)
			$offset = 'o' . $i . ' ';
		if ($i == 7)
			$offset = 'o5 ';
		if ($i == 8)
			$offset = 'o4 ';
		if ($i == 9)
			$offset = 'o3 ';
		if ($i == 10)
			$offset = 'o2 ';
		if ($i == 11)
			$offset = 'o1 ';
		if ($i > 11) {
			$i = 0; // Reset du compteur
			$offset = '';
		}
Modérateur
Salut Olivier,

Je propose un truc du genre :
//init :
$i = 1;
$up = true;

// [...]
// dans la boucle :
  if ($i == 1) {
    $up = true;
  }
  if ($i == 6) {
    $up = false;
  }

  if ($up) {
    $i++;
  } else {
    $i--;
  }


Mais tu devrais aussi pouvoir jouer avec la $key du foreach non ?
Modifié par _laurent (13 Jun 2016 - 15:52)
@_laurent : Merci, le code est ainsi bien plus propre :
	$i = -1; // Permet de passer la première itération
	$up = true;
	foreach ( $commentsArray as $e ) {
		if ( $i == 0 )
			$up = true;
		if ( $i == 6 )
			$up = false;
		if ( $up ) {
			$i++;
		} else {
			$i--;
		}
		if ( $i == 0 ) {
			$offset = '';
		} else {
			$offset = 'o' . $i . ' ';
		}
	// Le reste du code...
	}

Modifié par Olivier C (13 Jun 2016 - 17:37)
Olivier C a écrit :
@_laurent : Merci, le code est ainsi bien plus propre :
	$i = -1; // Permet de passer la première itération
	$up = true;
	foreach ( $commentsArray as $e ) {
		if ( $i == 0 )
			$up = true;
		if ( $i == 6 )
			$up = false;
		if ( $up ) {
			$i++;
		} else {
			$i--;
		}
		if ( $i == 0 ) {
			$offset = '';
		} else {
			$offset = 'o' . $i . ' ';
		}
	// Le reste du code...
	}

Etant donné que PHP n'est pas mon langage au quotidien, j'ai essayé, à titre d'exercice, de réécrire ce code de façon plus compacte, comme je l'aurais fait sous Java :
<?php
$limit=7; // Rend le script générique
$break= $limit-1; // Permet de limiter les calculs dans la boucle
$step=1; // Décalage initial
$i = 0; // Valeur initiale de l'indice
	for ( $index = 0 ; $index < 30 ; $index++ )
	{
		$offset = $i == 0 ? '' : 'o' . $i . ' ';  // Texte formaté
                // Juste pour voir...
		echo sprintf("%'.03d",$index) . ' i [' . $i . '] - offset [' . $offset . "]\n";		
                // En remplacement du test ternaire faisant partir PHP en vrille
		switch ($i)
		{
			case 0 : 
				$step = 1; 
				break;
			case $break : 
				$step = -1; 
				break;
		}		
                // Ancien test ternaire que PHP ne reconnaît pas
//		$step = $i == 0 ? 1 : $i == $break ? -1 : $step;		
		$i += $step;  // Actualisation de l'indice		
	}
?>

Résultat :
000 i [0] - offset []
001 i [1] - offset [o1 ]
002 i [2] - offset [o2 ]
003 i [3] - offset [o3 ]
004 i [4] - offset [o4 ]
005 i [5] - offset [o5 ]
006 i [6] - offset [o6 ]
007 i [5] - offset [o5 ]
008 i [4] - offset [o4 ]
009 i [3] - offset [o3 ]
010 i [2] - offset [o2 ]
011 i [1] - offset [o1 ]
012 i [0] - offset []
013 i [1] - offset [o1 ]
014 i [2] - offset [o2 ]
015 i [3] - offset [o3 ]
016 i [4] - offset [o4 ]
017 i [5] - offset [o5 ]
018 i [6] - offset [o6 ]
019 i [5] - offset [o5 ]
020 i [4] - offset [o4 ]
021 i [3] - offset [o3 ]
022 i [2] - offset [o2 ]
023 i [1] - offset [o1 ]
024 i [0] - offset []
025 i [1] - offset [o1 ]
026 i [2] - offset [o2 ]
027 i [3] - offset [o3 ]
028 i [4] - offset [o4 ]
029 i [5] - offset [o5 ]

Problème : j'ai dû remplacer la comparaison ternaire par une instruction switch car, dixit l'aide en ligne PHP :
a écrit :
Note:
Il est recommandé de ne pas "empiler" les expressions ternaires. Le comportement de PHP lors de l'utilisation de plus d'un opérateur ternaire dans une seule instruction n'est pas évident.

Et là, je reste dubitafif devant PHP... Smiley eek
L'instruction :
$step = $i == 0 ? 1 : $i == $break ? -1 : $step;

passe parfaitement en Java ou C# et reste lisible.
Si PHP part en vrille sur une instruction aussi simple, ma considération pour ce langage vient d'en prendre un sérieux coup. Smiley rolleyes
Si quelqu'un a un avis sur le sujet, je suis preneur...

PS : Quand je dis que j'ai réécrit de façon "plus compacte", cela s'entend bien sûr une fois le code ci-dessus débarrassé des commentaires et des affichages de trace, la boucle se résumant alors en Java à...
$offset = $i == 0 ? '' : 'o' . $i . ' ';
... Utilisation du texte ...
$step = $i == 0 ? 1 : $i == $break ? -1 : $step;
$i += $step;

Modifié par sepecat (13 Jun 2016 - 22:13)
Je n'y connais pas grand chose en php, c'est pour cela que je demande des conseils pour optimiser. Je viens par exemple de découvrir que j'aurais pu créer ma condition à partir des restes (%). Par exemple pour ajouter une classe sur les itérations paires, puis une autre pour les impaires :
		$i2++;
		if ( $i2 % 2 == 0 ) { // Teste si l'itération est paire ou impaire.
			$offsetSize = 'sizeS-o0 ';
		} else {
			$offsetSize = 'sizeS-o3 ';
		}

Modifié par Olivier C (14 Jun 2016 - 06:41)
Olivier C a écrit :
Je n'y connais pas grand chose en php, c'est pour cela que je demande des conseils pour optimiser. Je viens par exemple de découvrir que j'aurais pu créer ma condition à partir des restes (%). Par exemple pour ajouter une classe sur les itérations paires, puis une autre pour les impaires :
		$i2++;
		if ( $i2 % 2 == 0 ) { // Teste si l'itération est paire ou impaire.
			$offsetSize = 'sizeS-o0 ';
		} else {
			$offsetSize = 'sizeS-o3 ';
		}

Pour être exact, en première approche du problème j'avais aussi envisagé de recourir au reste de la division entière (modulo) pour basculer suivant que l'on se trouve avant ou après une valeur pivot (7 en l'occurrence).
En ayant lu le commentaire de Laurent, je suis toutefois parti sur cette base pour mon petit exercice perso.
Et là, ça a été deux heures de galère pour comprendre pourquoi ce foutu test ternaire ne fonctionnait pas (le step partait de suite en -1 et n'en bougeait plus), alors que la même instruction avec des IF fonctionnait sans problème.
Venant de Java et C#, j'avoue avoir mis un certain temps à envisager que ce soit la combinaison des deux tests ternaires qui courait, tellement cela paraît aberrant sur le principe...
Après avoir fureté du côté du manuel PHP en ligne et lu l'avertissement que je cite, j'ai un peu mieux compris le côté un peu olé olé du langage sur ce point.
Offrir la possibilité d'utiliser un instruction, mais pas trop parce que sinon cela risque de donner des résultats aléatoires... je n'avais quasiment jamais vu ça auparavant.
Je lisais récemment un article qui affirmait avec certitude que PHP n'était pas un langage d'entreprise... Sur le moment, cette affirmation me semblait étonnante vu le nombre de sites web mettant en oeuvre ledit langage.
Je comprends mieux aujourd'hui ces réserves...
Pour être clair, au boulot je n'ai pas entendu une seule équipe me citer un développement web en PHP ces dernières années.
Tout repose sur Java / JSP, langage auquel on peut trouver un certain nombre de défauts mais qui accepte lui, sans broncher, cinq à six tests ternaires sur une même ligne.
Certains refusent ce type de rédaction, le jugeant illisible. C'est un faux débat et juste une question d'habitude. En tout cas, une instruction annoncée comme disponible DOIT fonctionner en toute circonstance et non pas de temps en temps, qui plus est sans afficher d'erreur autre qu'un résultat aléatoire.
Ayant testé mon bout de code sur deux sites en ligne, avec des résultats tout aussi aberrants à chaque fois, je me dis que j'ai intérêt à regarder tout ceci de très près lorsque mon générateur HTML en viendra à produire du PHP...
L'avantage, c'est qu'en cas de comportement foireux avéré je pourrai basculer facilement d'un type d'instruction à un autre.
Administrateur
sepecat a écrit :

Problème : j'ai dû remplacer la comparaison ternaire par une instruction switch car, dixit l'aide en ligne PHP :
-----
Note:
Il est recommandé de ne pas "empiler" les expressions ternaires. Le comportement de PHP lors de l'utilisation de plus d'un opérateur ternaire dans une seule instruction n'est pas évident.
-----
Et là, je reste dubitafif devant PHP... Smiley eek
L'instruction :
$step = $i == 0 ? 1 : $i == $break ? -1 : $step;

passe parfaitement en Java ou C# et reste lisible.
Si PHP part en vrille sur une instruction aussi simple, ma considération pour ce langage vient d'en prendre un sérieux coup. Smiley rolleyes
Si quelqu'un a un avis sur le sujet, je suis preneur...

Où est-ce qu'il y a imbrication d'opérateurs ternaires ? Je n'en vois pas ici (mais j'ai pas lu le sujet suffisamment en détail peut-être ?)

En PHP, l'une des écritures est
(test) ? $a = valeur1 si c'est true : $b = valeur2 si c'est false;

L'autre étant
variable_à_affecter = (test) ? valeur_si_true : valeur_si_false;

Doc : https://secure.php.net/manual/fr/language.operators.comparison.php#language.operators.comparison.ternary
Felipe a écrit :

Où est-ce qu'il y a imbrication d'opérateurs ternaires ? Je n'en vois pas ici (mais j'ai pas lu le sujet suffisamment en détail peut-être ?)

En PHP, l'une des écritures est
(test) ? $a = valeur1 si c'est true : $b = valeur2 si c'est false;

L'autre étant
variable_à_affecter = (test) ? valeur_si_true : valeur_si_false;

Doc : https://secure.php.net/manual/fr/language.operators.comparison.php#language.operators.comparison.ternary

Bin, sauf erreur il y en a deux sur cette instruction :
$step = $i == 0 ? 1 : $i == $break ? -1 : $step;

Le premier teste la valeur nulle, le second teste le point pivot.
Deux "?" dans l'expression = deux tests ternaires, du moins est-ce considéré comme tel en Java. A priori, je n'ai rien lu en PHP qui dénote une approche contraire dans ce langage.
N'étant pas un pro dudit langage et s'il y a erreur d'appréciation, je suis ouvert à toute contradiction sur le sujet.
Pour exemple, une expression que j'utilise souvent en Java pour sécuriser l'accès par clé sur une table de hachage :
if (x == nul ? false : (items == null ? 0 : items.size()) == 0 ? false : items.conrainsKey(x)) { ... }

Un peu frapadingue, mais ça fonctionne nickel et couvre tous les cas de figure...
Modifié par sepecat (14 Jun 2016 - 19:56)