begin process at 2010 02 10 01:26:00
  Trouver un code source :
 
dans
 
Accueil > 

Tutoriels

 > 

Astuces

 > Les énumérations (enum) en php

Les énumérations (enum) en php


 Information sur le tutoriel

Note :
Aucune note


 Description

Le langage php ne disposant pas de cette notion qui est pourtant essentielle à la lisibilité d'un programme, je propose ici quelques solutions pour « simuler » ce concept.

Tutorial

Solution 1 : la liste de constantes

Cette solution est valable à partir de la version 4 de php.

L'énumération est un mécanisme de synonymie entre un ensemble de valeurs constantes et un ensemble de noms de variables d'un même espace de noms.

Le mécanisme de synonymie le plus classique est celui de la constante. Les langages qui acceptent ce mécanisme permettent de déclarer et d'utiliser un nom, généralement en visibilité globale, à la place d'une valeur scalaire qui ne sera pas modifiée au cours du temps d'exécution d'un programme.

En php, on écrira :

define ("maConstante" , 5.5);

et pour faire un test de valeur, on écrira quelquechose comme :

if ($maVariable === maConstante)
 faireAvec();
else
 faireAutrement();

Les constantes sont le moyen le plus simple de simuler une énumération. Mais aussi le moins puissant.

Par exemple, si on doit manipuler une liste de noms de systèmes d'exploitation, on pourrait déclarer :

define ("Linux" , 0);
define ("Mac" , 1);
define ("Windows" , 2);

Ainsi lorsqu'on veut faire un test de valeur sur une variable de ce type, on écrira :

switch ($maVariable) {
 case Linux : faireAvecLinux(); break;
 case Mac : faireAvecMac(); break;
 case Windows : faireAvecWindows(); break;
}

Ce qui est plus lisible que :

switch ($maVariable) {
 case 0 : faireAvecLinux(); break;
 case 1 : faireAvecMac(); break;
 case 2 : faireAvecWindows(); break;
}

Cette solution ravira les plus désoeuvrés, mais ne contentera pas les plus exigeants. En effet, dans une liste de constantes, les noms ne sont pas reliés ensemble au sein d'un même groupe et peuvent même être déclarés séparément dans le code source. Ils sont juste placés côte à côte par commodité.

Maintenant lorsqu'on a un ensemble de valeurs constantes qui ont une signification commune, il est plus commode de les regrouper dans un même espace de noms qui ont un sens du point de vue de la lisibilité du programme.

Solution 2 : les clés d'un tableau associatif

Cette solution est valable à partir de la version 4 de php.

La grande force des tableaux en php, c'est que derrière chaque tableau se cache un tableau associatif. Le tableau traditionnel associe des entiers consécutifs à des valeurs d'un certain type, le tableau associatif associe des valeurs d'un type arbitraire à des valeurs d'un autre type. C'est une forme de généralisation de la notion de tableau.

En général, on déclare un tableau associatif de cette manière :

<?php
$array = array( 1, 1, 1, 1,  1, 8=>1,  4=>1, 19, 3=>13);
print_r($array);
?>

L'exemple ci-dessus va afficher :

Array
(
    [0] => 1
    [1] => 1
    [2] => 1
    [3] => 13
    [4] => 1
    [8] => 1
    [9] => 19
)

Pour créer une énumération, on procèdera ainsi :

$OS = array ("Linux"=>0, "Mac"=>1, "Windows"=>3);

Et pour faire un test de valeur, on écrira :

switch ($maVariable) {
 case $OS["Linux"] : faireAvecLinux(); break;
 case $OS["Mac"] : faireAvecMac(); break;
 case $OS["Windows"] : faireAvecWindows(); break;
}

On fait ici une utilisation moins courante du tableau d'association, puisqu'on utilise les chaînes de caractères comme clés de recherche dans le tableau et les indices comme valeurs du tableau. Mais cette forme de langage permet de préciser deux choses :

- les valeurs possibles de maVariable sont remplacées par des expressions claires qui exprime ce que la variable contient ("Linux", "MasOS" et "Windows" est bien plus clair que 0, 1 et 2). Ce qui augmente la lisibilité d'un programme.
- les valeurs possibles de maVariable sont restreintes à un espace de noms clairement défini (celui des systèmes d'exploitation pour cet exemple). Ce qui augmente encore plus la lisibilité et la compréhension d'un programme.

Noter que la version courte, bien que tentante, ne fonctionnera pas :

$OS = array ("Linux", "Mac", "Windows");

Puisque le préprocesseur php attribuera automatiquement les indices, c'est l'équivalent de :

$OS = array (0=>"Linux", 1=>"Mac", 2=>"Windows");

Hors l'astuce utilisée ici se sert de la clé d'association comme élément de langage.

Solution 3 : Les énumérations statiques de classes

Cette solution n'est utilisable qu'à partir de la version 5 de php.

La classe est une unité de programmation qui représente un concept manipulé par le programme. Il est commode de disposer d'énumérations relatives à une classe ou un concept. Ce qui permet de rendre toujours plus lisible et compréhensible un programme.
Cette solution n'en est pas vraiment une, mais plutôt une extension de la solution précédente, à la programmation objet.

Avec la version 4 de php qui inclut la première, les concepts de programmation objet, on pourrait déclarer le tableau $OS dans une classe conteneur, mais il en deviendrait membre et serait répliqué inutilement avec toutes les instances de la classe conteneur. Ce n'est qu'avec la version 5 de php, qui intègre la notion de membre de classe statique, que l'astuce suivante pourra être utilisée.

Par exemple, si le programme opère des transactions avec le système sur lequel il est installé, on pourra créer une classe System :

class System {

 public static $OS = array("Linux"=>0, "Mac"=>1, "Windows"=>3);
 public static $LinuxFamily = array("debian"=>0, "suze"=>1, "ubuntu"=>3);

 private $name;
 private $family;
 private $version;

 /* Constructeur */
 public __construct($name, $family, $version) {
  $this->name = $name;
  $this-> family = $family;
  $this->version = $version;
 }

 /* Accesseur */
 public function getName() { return $this->name; }

 ...

}

et pour déclarer une variable du type System, on écrira :

$monSysteme = new System(System::$OS["Linux"], System::$LinuxFamily["ubuntu"], "7.10");

Ce qui est forcément plus lisible que :

$monSysteme = new System(0, 3, "7.10");

De la même manière, pour faire un test de valeur, on écrira :

switch ($monSysteme->getName()) {
 case System::$OS["Linux"] : faireAvecLinux(); break;
 case System::$OS["Mac"] : faireAvecMac(); break;
 case System::$OS["Windows"] : faireAvecWindows(); break;
}

Conclusion

Ce document vous a présenté trois techniques qui permettent de pallier à l'absence de la notion d'énumération dans le langage php. Elle ne sont pas très élégantes, mais elles permettent au moins d'apporter plus de lisibilité au code.

Quelques faiblesses de ces techniques :

- Lourdeur d'écriture : comme le php ne dispose des mécanismes propres aux énumérations (nommage, raccourci de langage...), il est nécessaire de faire quelques abus de langage (utilisation inverse des tableaux d'association) pour utiliser la simulation.
- Aucun contrôle de type (appartenance de la valeur d'une variable à l'espace de valeurs défini par l'énumération) ne peut être réalisé sur les variables manipulant ces énumérations, à moins de contorsion de langage périlleuses qui auront tendance à obscurcir le code.

Il s'agit juste de solutions temporaires, en attendant que les développeurs de php intègrent enfin cette notion au langage...
Il faut savoir être patient, le langage java n'intègre cette notion que depuis la version 5 (mais avec brio puisque la notion d'énumération est complètement intégrée à la notion de classe).

Commentaires

Commentaire de malalam le 30/12/2007 14:13:35 administrateur CS

Hello,

intéressant!!
On peut aller un peu plus loins côté PHP5. Un exemple fait à la va vite, mais on peut sans doute faire bcp mieux (philosophie complètement différente de ce que tu présentes) :
<?php
class typeException extends Exception {}

abstract class enumType {
public function __toString() {
return get_class($this);
}
}

abstract class enum {
protected $enum;

public function set($sEnumType) {
if(!in_array($sEnumType, $this->enum) || !class_exists($sEnumType)) {
throw new typeException($sEnumType.' is not a valid '.get_class($this).' type');
}
return new $sEnumType;
}
}

class cards extends enum {
public function __construct () {
$this->enum = array('CARREAU', 'PIQUE', 'TREFLE', 'COEUR');
}
}

class CARREAU extends enumType {}
class PIQUE extends enumType {}
class COEUR extends enumType {}
class TREFLE extends enumType {}

try {
$cards = new cards;
$a = $cards->set('PIQUE');
echo $a.'<br />';
if($a instanceof PIQUE) {
echo 'ok';
} else {
echo 'ko';
}
echo '<hr />';
$b = $cards->set('DIAMOND');
} catch(typeException $e) {
echo $e;
}
?>

Commentaire de malalam le 30/12/2007 14:23:14 administrateur CS

J'arrive pas à noter désolé, petit bug temporaire sans aucun doute. On verra plus tard. Mais 10/10 pour moi, idée intéressante :-)

Commentaire de AlexN le 30/12/2007 20:06:03

Salut,

Ta solution est aussi intérressante. Elle s'approche plus de la notion java d'énumération, en apportant un meilleur contrôle sur le type des instances. Par contre, elle a des lourdeurs d'écriture qui nuisent à la lisibilité (et aux performances) :

- Il faut définir plusieurs classes avant de pouvoir déclarer une énumération elle même
- Il y a des répétitions dans les déclarations, 'CARREAU' puis class CARREAU, 'PIQUE' puis class PIQUE
- Cette "double déclaration" du type final entraine un double contrôle (!in_array($sEnumType, $this->enum) || !class_exists($sEnumType))

Je dirais que les solutions que j'ai proposé sont des solutions rapides et utilisables uniquement dans un environnement controlé (le développeur sait exactement ce qu'il met dans ses variables et peut se passer des controles de type), tandis que ta solution, conviendra mieux à une application ouverte (comme une API, par exemple) où l'énumération pourra être utilisée par d'autres développeurs à qui il faudra fournir un mécanisme de contrôle de type.

C'est la "solution 4".

Merci pour ta participation.

Commentaire de coucou747 le 02/01/2008 16:37:11

en fait, seul la solution de malalam est satisfaisante, un enum c'est pas seulement des nombres, on n'utilise jamais les nombres, un enum c'est un type a part entiere,,,

Commentaire de malalam le 02/01/2008 21:48:14 administrateur CS

Bon bah je voulais répondre mais Coucou a résumé le fond de ma pensée lol.
Ce qui me pose problème dans tes solutions, c'est en effet le manque de "typage". Tes solutions ne permettent pas de vérifier que l'on assigne bien une valeur correcte de l'énumération, de tester ces valeurs, d'en comparer...mon exemple n'est pas complet, mais il va dans ce sens.

Commentaire de AlexN le 03/01/2008 00:18:32

Je ne comprend pas trop ce que tu veux dire par "on utilise jamais les nombres". Les énumérations sont des synonymes de valeurs entières (des nombres). Les enumérations que je connais du langage c sont simplement des associations de constantes nommées à des valeurs entières (et ça marche très bien sans aucun contrôle de type quelconque). A chaque nom est associé une valeur (ou un nombre). Et derrière chaque énumération, on trouve un sous ensemble des entiers, alors quel est l'interêt du controle de type d'une énumération ?

Commentaire de FhX le 03/01/2008 15:15:48

L'enum a proprement parler, c'est ca :

class enum {
const _x_ = 'truc';
const _y_ = 1;
const _z_ = 3.14;
}

$mavar = 'truc';
switch ($mavar) {
  case enum::_x_ :
        //
        break;
  case enum::_y_ :
        //
        break;
  case enum::_z_ :
        //
        break;
}

Rien de plus à la base :))

Commentaire de AlexN le 03/01/2008 17:05:47

Si on remonte aux temps immémoriaux, à la base une enum c'est ça :

enum Boolean {False, True};
enum Couleur {Bleu, Blanc, Rouge};
enum Sens {Gauche, Haut, Droite, Bas};

Ce n'est qu'une liste de mots associés à des valeurs entières.
Nul besoin de classe, ni même de type...

et si on voulait plus sophistiqué, on faisait :

typedef enum {
  e_sens_gauche,
  e_sens_haut,
  e_sens_droite,
  e_sens_bas
} e_sens;

@coucou : qu'appelles tu "solution satisfaisante" ?
Une solution qui satisfait ton esprit, ou une solution fonctionnelle. Parce que dans le second cas, tu aurais pu tester pour voir que ces solutions fonctionnent très bien.

Commentaire de AlexN le 03/01/2008 19:30:03

Sinon ce que tu as écrit fhx ce sont des constantes de classe, pas une énummération (il n'y a aucune relation entre les constantes, sinon qu'elles sont déclarées dans la même classe).

Commentaire de FhX le 04/01/2008 00:32:18

"Si on remonte aux temps immémoriaux, à la base ..."
"Nul besoin de classe, ni même de type..."

Grosse erreur.
Les classes n'existaient pas en ces temps immémoriaux mais le typage oui. Enum (en C à l'epoque) est bien un type. Sisi :)

D'ailleurs, tu le dis toi même :
"
typedef enum {
  e_sens_gauche,
  e_sens_haut,
  e_sens_droite,
  e_sens_bas
} e_sens;
"

Je me permet de corriger ce point :)

Maintenant en ce qui me concerne, qu'est ce qu'une énumération ? N'est ce pas un parcours d'éléments constants  ? Il me semble bien que si. A partir de la, on peut établir plusieurs schémas :
- Soit le type existe et on utilise les caractéristiques du typage (comme en C/C++)
- Soit on utilise un tableau de constante ( auquel cas une ptite recherche est necessaire sur les clefs du tableau )
- Soit on utilise une classe de constante.


Une relation de constante ? Qu'est ce que tu appèles une relation de constante ? Un groupement de constantes sur une partie de code spécifique ? Alors dans ce cas, regrouper les constantes dans une même classe peut établir une relation entre les constantes.

Je te conseil de regarder le modèle de Java hautement orientée objet (puisque je ne touche plus au procédurial depuis un moment ^^). Tu verras que l'énumération est desormais utilisée en tant que classe :)


Voila :)

Commentaire de AlexN le 04/01/2008 12:36:56

lol c'te bataille de clocher..
Alors moi aussi je corrige tes erreurs :

1) Tu ne sembles pas connaitre (ou te souvenir) des subtilités du langage c. Je dis deux choses :

enum Boolean {False, True};

puis

typedef enum { False, True } Boolean;

Ce sont deux expressions complètements différentes. Les deux ne peuvent pas coexister dans le même programme (erreur de compilation).
La première expression est la déclaration d'une énumération. IL N'Y A AUCUNE DECLARATION DE TYPE DANS CETTE INSTRUCTION.
Il s'agit en fait d'un raccourci pour :

enum Boolean {False = 0, True = 1};

Cette expression déclare que la chaine "False" est désormais synonyme de la valeur 0 et que la chaine "True" est désormais synonyme de la valeur 1. Les types sont déjà identifiés clairement. CE SONT DEUX ENTIERS.

La seconde expression déclare que Boolean est un synonyme de l'énumération anonyme qui contient deux chaines "False" et "True" qui sont synonymes de deux valeurs entieres (0 et 1)

Si j'avais écrit :

typedef enum { "False" = 75, "True" = 89 } Boolean;

j'aurais déclaré que Boolean est un synonyme de l'énumération anonyme qui contient deux chaines qui sont synonymes de deux valeurs entieres (75 et 89).

Le mot typedef est un faux ami en c, il ne déclare ni ne construit de nouveau type de données. Il ne fait que déclarer un synonyme d'un type existant.

autre exemple :

struct Date {
        int         j;   /* Jour */
        enum Mois   m;   /* Mois */
        int         a;   /* - */
};

Cette instruction déclare un type de données (ce coup ci) nommé date .

typedef struct myDate {
        Jour   j;
        Mois   m;
        Anne   a;
} Date;

Cette instruction déclare que "Date" est synonyme du type de données nommé myDate.

Donc pour revenir à ce qui nous concerne, il n'a a aucune erreur, l'expression enum Boolean { "False", "True" } n'est pas une déclaration de type. Et l'expression typedef enum { "False", "True" } Boolean n'en est pas une non plus.

2) Une énumération est "à la base" juste une liste de mots que l'on déclare comme étant synonymes de valeurs constantes et entières. C'est un artifice du langage qui apporte une meilleure lisibilité au programme (il est toujours plus clair de comprendre avec maVar = Lundi que maVar contient un indice de jour qu'avec maVar = 0). Maintenant quand un langage ne dispose pas de ce mécanisme, il existe plusieurs solutions pour l'utiliser ("simuler" comme je dis bien en haut du tuto, si tu l'as lu). C'est juste ce que je propose.

3) Alors oui, j'ai suivi de près l'évolution du concept d'énumération jusque dans java, et même eu les occasions d'utiliser l'extension de ce concept en tant que classe. Il est riche et puissant. Mais je dis ceci : ce n'est pas parce qu'on est à l'époque de la programmation objet, que tout doit être objet. Cela peut nuire. Exemple java :

for (int i = 0; i < 2; i++);
for (Integer i = 0; i < 2; i++);

la première instruction utilise un type primitif, la seconde utilise un objet de classe Integer. La seconde instruction est un abus d'objet et elle entraine des opérations inutiles (création d'un objet sur le tas, controles de type pour chaque opération sur l'objet, destruction d'objet (garbage collecting)), tout ça pour une vulgaire itération. Si chaque fois que tu as besoin d'un indice de boucle, tu crées un objet, tu fais fausse route.
De la même manière, si chaque fois que tu as besoin d'une énumération, tu crées une classe, tu fais fausse route.. si tu peux utiliser des mécanismes simples et rapides, autant en profiter.

4) Relation entre constantes : les énumérations ne sont pas seulement une liste de mots associés à des valeurs. Mais l'ensemble de ces mots constitue une entité du programme : la liste des noms des jours de la semaine, la liste des synonymes des valeurs booléenne, etc. C'est pour ça que je dis que la solution de la liste de constantes n'est pas suffisante parce les constantes peuvent être déclarées n'importe où dans le source et sans relation établie (à par le fait d'être déclarée dans la même classe, le même fichier, etc). Tandis que lorsqu'on écrit :

$OS = array ("Linux"=>0, "Mac"=>1, "Windows"=>3);

on établi une relation plus forte entre les mots "Linux", "Mac et "Windows" qui sont les éléments d'une même entité (le tableau des noms d'os).

Fiouuuuu

Commentaire de guilhemmartincpp le 07/01/2008 17:59:33

Merci pour le tuto, 3 approches intéressantes. Je viens de débarquer dans le monde PHP et je me demandais justement s'il y avait qqchse comme enum...
La discussion qui suit le tuto n'en est pas moins intéressante ;).

Commentaire de AlexN le 07/01/2008 23:15:38

4 (quatre) solutions. Celle de Malalam en est une autre plus orientée objet (php5). :o)

Commentaire de guilhemmartincpp le 08/01/2008 13:57:46

Re-Bonjour,

je n'arrive pas à comprendre pourquoi le code suivant ne fonctionne pas. Est-ce que je loupe quelque chose d'évident ?
Le code suivant
[code]
$OS = array ("Linux"=>0, "Mac"=>1, "Windows"=>3);
$maVariable="Windows";
switch ($maVariable) {
case $OS["Linux"] : echo "faireAvecLinux"; break;
case $OS["Mac"] : echo "faireAvecMac"; break;
case $OS["Windows"] : echo "faireAvecWindows"; break;
}
[/code]
m'affiche toujours "Linux".
Merci.

Commentaire de AlexN le 08/01/2008 21:42:25

Parce que tu as confondu la chaîne de caractères "Windows" qui vaut "Windows" avec la valeur de la variable $OS["Windows"] qui vaut 3.
Ecris plutôt :

$OS = array ("Linux"=>0, "Mac"=>1, "Windows"=>3);
$maVariable=$OS["Windows"]; // ou $maVariable=3;
switch ($maVariable) {
  case $OS["Linux"] : echo "faireAvecLinux"; break;
  case $OS["Mac"] : echo "faireAvecMac"; break;
  case $OS["Windows"] : echo "faireAvecWindows"; break;
}

Par contre, tu as mis le doigt sur un comportement de php que je ne connaissais pas et qui me semble étrange. Pour quelle raison il associe la chaîne de caractères "Windows" à la valeur 0 ?
Ce comportement semble lié au faible typage du langage, parce que si tu écris $maVariable = "3" tu auras comme réponse "faireAvecWindows". On dirait que php présume le type de $maVariable par rapport à l'ensemble des valeurs de l'instruction switch et qu'il tente un transtypage de la chaîne "Windows" en valeur du tableau $OS ("Windows" est une clé du tableau $OS, pas une de ses valeurs). Comme le transtypage échoue, il renvoie la valeur du premier élément du tableau (inverses "Linux"=>0, "Mac"=>1 par "Linux"=>1, "Mac"=>0 et tu verras que la réponse par défaut lors d'un transtypage raté devient "Mac").
Encore pire, si le tableau ne contient aucune valeur 0 et que le transtypage échoue, php ne retourne aucune valeur valide (default:).
On dirait bien un bug de langage. Enfin si quelqu'un veut bien nous éclairer...

Commentaire de malalam le 09/01/2008 08:16:39 administrateur CS

Hello,

ce n'est pas un bug. Il s'agit du comportement normal et défini de PHP.
Laisser la conversion implicite de PHP faire du transtypage d'une chaîne vers un entier fonctionne à peu près ainsi :
"3" == 3
"3Windows" == 3
"Windows" == 0
"Windows3" == 0
Vous pourrez trouver l'ensemble des comportements sur la doc de php, il y a quelque part une table résumant les comparaisons de types.

Bref, dans notre cas, PHP ne va absolument pas chercher la 1ère valeur du tableau par défaut. D'ailleurs, changez juste la valeur de la clef "Linux" pour mettre 2 par exemple etr relancez le code : aucun echo ne s'affichera.
Il va simplement chercher le "case" correspondant au résultat de la conversion implicite qu'on lui demande de faire : le case 0.

Commentaire de guilhemmartincpp le 09/01/2008 08:45:37

Merci pour le coup de main ... et pour le nouveau rebondissement déclenché ;)

Commentaire de AlexN le 09/01/2008 18:57:13

Merci pour tes précisions Malalam.

Commentaire de malalam le 09/01/2008 22:03:16 administrateur CS

Je voulais ajouter quelque chose mais ce matin je n'ai pas eu le temps (faut bien aller bosser!). Si on se trouve dans ce cas-ci, là, c'est effectivement à cause du switch.
En PHP, switch fait de la "loose comparison" (loose, pas lose hein...quoique...), il n'y a pas moyen (pour le moment en tous cas) de le forcer à faire des comparaisons strictes (comme on peut le faire avec une fonctionne comme in_array() par exemple...mais switch n'étant pas une fonction, ce n'est pas gagné. M'enfin...).
C'est pour ça que personnellement, je ne m'autorise l'utilisation de switch que lorsque je suis SÛR que les variables à comparer seront du même type. Sinon, un un if elseif est à mon sens nettement préférable, on peut au moins y faire des comparaisons strictes.

J'en profite pour insister sur le fait que les comparaisons non strictes sont réellement dangereuses et peuvent franchement causer de gros problèmes. Un exemple :
<?php
$a = 'test';
$b = '';
$c = 1;
$d = 0;
$e = true;
$f = false;

/*
Logiquement, si a = c ET b = c, on est d'accord pour dire que a = b.
Vérifions!
*/
if($a == $e) {
echo "ok\n"; // ok! bon...donc 'test' == true
} else {
echo "ko\n";
}
if($c == $e) {
echo "ok\n"; // ok! alors, 1 == true
} else {
echo "ko\n";
}
// donc...$a == $c ('test' == 1) logiquement!
if($a == $c) {
echo "ok\n";
} else {
echo "ko\n"; // ah ben non...
}

/*
Continuons dans le même ordre d'idée!
*/
if($b == $f) {
echo "ok\n"; // ok! bon...donc '' == false
} else {
echo "ko\n";
}
if($a == $d) {
echo "ok\n"; // ok! alors 'test' == 0
} else {
echo "ko\n";
}
if($f == $d) {
echo "ok\n"; // ok! et false == 0
} else {
echo "ko\n";
}
// alors 'test' == false == 0 == '' ou pour pour raccourcir 'test' == '' ??? wtf??
if($a == $b) {
echo "ok\n";
} else {
echo "ko\n"; // non...ouf, dans un sens ça rassure, mais d'un autre côté...ça fait peur, non ?
}
?>

Commentaire de malalam le 09/01/2008 22:06:03 administrateur CS

// alors 'test' == false == 0 == '' ou pour pour raccourcir 'test' == '' ??? wtf??
=> il faut lire pour respecter l'ordre :
// alors 'test' == 0 == false == '' ou pour pour raccourcir 'test' == '' ??? wtf??
parce qu'en fait, 'test' == true. Eh vi...

Commentaire de AlexN le 10/01/2008 14:45:20

Oui pas très commode comme comportement. Je me suis renseigné et je comprend mieux.
En fait, php dispose de deux modes de comparaison. Mode strict (===) et mode large (loose avec ==).
Le mode strict est celui auquel on est habitués dans les autres langages (un objet est égal à un autre si et seulement si ils ont les mêmes valeurs de propriétés et s'ils sont de même type).
Le mode large php fait des conversions de types selon un jeu de règles.
Les règles de comparaison en mode large ne sont pas très simples.
C'est peut être pour faciliter la réception des paramètres de requête (GET/POST...) qui n'envoient que des chaines de caractères mais qui peuvent contenir toute sorte de type (des valeurs entières, des valeurs flottantes, des chaines de caractères..)
Alors ok, utiliser les mécanismes de conversion implicite de php, cela donne une plus grande richesse au langage mais à mon avis au détriment de la lisibilité. Parce que celui qui développe un script sera exactement ce qu'il attend comme paramètre au moment où il l'écrit. Mais s'en souviendra-t-il six mois plus tard, lorsqu'il relit son script et que toutes les conversions sont masquées par php. Cela ne rend pas php très accessible.

Alors en effet, Malalam, wtf ???
Pour moi la poo avait justement cet avantage de permettre un typage fort.
Mais je découvre que des langages modernes rejètent cette idée pour permettre des choses que je ne me serais pas permis avec la poo.
Regardes la notion d'héritage dynamique en javascript, les objets peuvent changer de propriétés voire même de parent au cours de leur existence.
Regardes avec php la possibilité de convertir des types en d'autres de manière implicite avec une flopée de règles à s'arracher les cheveux.
Si ça continue, l'instruction goto va revenir en force.

quelques liens pour ceux qui suivent la discussion :

http://www.blueshoes.org/en/developer/php_cheat_sheet/
http://fr.php.net/manual/fr/types.comparisons.php
http://fr.php.net/manual/fr/language.operators.comparison.php
http://www.syntaxpolice.org/index.php/?q=node/419
http://laffers.net/tools/php-comparisons.php
http://www.programmersparadox.com/2007/12/19/php-insanity/
http://fr.wikipedia.org/wiki/Relation_d'ordre
http://www.webmaster-hub.com/publication/Tester-correctement-variables-et.html
http://en.wikipedia.org/wiki/Monads_in_functional_programming
http://www.programmersparadox.com/2007/12/26/the-maybe-operator/

J'aime bien le dernier, l'opérateur "peut être" :

programmeur : Alors dis moi php, est-ce que a == b ?
php : ben...peut être... Sinon ça va la santé (mentale) ?

Dans le même ordre, on pourrait avoir l'opérateur "pourquoi pas". Nan ?

Commentaire de malalam le 10/01/2008 19:33:34 administrateur CS

Il faut comprendre l'historique de PHP : ce qu'il est devenu n'a aucun rapport avec ce pour quoi il a été créé. Il a été voulu, au départ, comme un langage de script web simplissime; le but était de permettre aux développeurs de monter très vite des pages web avec autre chose que du html (des pages un minimum dynamiques).
Et en cette époque reculé, les problèmes de sécurité n'étaient pas les mêmes. De plus, le langage étant beaucoup plus simple qu'auhourd'hui, la comparaison "loose" ne posait pas vraiment de problèmes, que des avantages.
PHP a évolué...mais au fil de ses évolutions, il est obligé de conserver une certaine rétro compatibilité. Et il n'y a qu'à lire la plupart des codes PHP pour se rendre compte que la comparaison "loose", si on la virait de php, poserait d'énormes problèmes : 95% des codes ne fonctionneraient plus.

Si tu t'intéresses à la programmation "moderne", jette un oeil à Ruby, et pour le web plus particulièrement au framework Ruby On Rails : tu verras à mon avis vers quoi on tend. Même si PHP restera à mon sens LE langage web pendant très longtemps...ROR est une alternative très intéressante dont la philosophie est complètement différente. Quand PHP se rapproche ostensiblement de Java, Ruby On Rails, lui, s'en éloigne le plus possible.

Quant à Javascript, ça a toujours été, et ça reste, un ovni. Mais un ovni extrèmement puissant et passionnant quand on se penche vraiment dessus.

Commentaire de FhX le 13/01/2008 22:24:36

Mala :
// alors 'test' == false == 0 == '' ou pour pour raccourcir 'test' == '' ??? wtf??
if($a == $b) {
echo "ok\n";
} else {
echo "ko\n"; // non...ouf, dans un sens ça rassure, mais d'un autre côté...ça fait peur, non ?
}

Non, car on utilise pas le comparateur == pour comparer 2 chaines.
On utilise strcmp(String, String) pour faire cela.

Tu ne peux pas déduire que :
'test' == 0 == false
'' == false
alors : 'test' == ''

Ca serait idiot d'ailleurs :)
La transitivité ne s'applique pas au type String. (d'ailleurs, elle ne doit pas s'appliquer tout court)


AlexN:
"Pour moi la poo avait justement cet avantage de permettre un typage fort. "
Elle permet un typage plus fort, mais seulement entre objet... pas avec des types primitifs.
ex :
public function addMonObjet(MonObjet $obj);
public function addMonAutreObjet(MonAutreObjet $obj);

Dans le cas d'un type primitif, il faut transtyper.

"Si ça continue, l'instruction goto va revenir en force." <== le rapport ?


Ruby est sympa aussi, il est assez proche de Python coté objet.
Mais le passage a Ruby et RoR nécessite un apprentissage de fond en comble :)

Commentaire de coucou747 le 14/01/2008 01:59:21

bien bien bien.... moi j'ai rate pas mal de discutions ici, j'ai aucune idee du pourquoi...

http://fr.php.net/manual/en/language.oop5.php#73929

ici on peut trouver un truc qui me semble carement plus "juste" par rapport a un langage comme le Cpp.

en Cpp ou en C#, un enum c'est "compile" comme un int, mais imaginons que vous ayez a faire une fonction comme :

public function JourDeLaSemaine_Is_WeekEnd(Day $jour)

Day c'est un enum ?

oui mais alors, le typage, il est utile ou pas ?

et dans ce cas, est-ce-que les solutions proposees plus haut sont satisfaisantes ?

http://www.phpcs.com/codes/ENUM-JAVA-LIKE-TYPAGE-FORT_45420.aspx

je prefere franchement ca, meme si ca n'est pas parfaitement souple

Commentaire de malalam le 14/01/2008 22:42:57 administrateur CS

@FhX => on n'est pas en type string, on est en multitype là. Je ne compare pas directement 2 types string, je passe par d'autres types pour en arriver là.
et strcmp() n'est pas plus douée que la comparaison stricte, elle fonctionne juste différemment :
par exemple dans ce cas, les 2 sont d'accord :
<?php
echo strcmp(0, '0');
echo (int)(0 == '0');
?>
parce que php convertit automatiquement 0 en '0'.

Et selon moi, la transitivité dans le cadre de comparaisons n'est pas idiot, bien au contraire, c'est vital! La comparaison stricte est d'ailleurs toujours transitive. Puisqu'on teste les types, il n'y a pas moyen de se planter.
Ca évite des abherrations de ce genre :
<?php
if('test' == true && 1 == true && 1 == 'test') {
echo 'ok';
}
?>
Parce que selon moi, c'en est une.
D'ailleurs, si on ne teste QUE des string, en comparaison laxiste, c'est toujours transitif.


Commentaire de AlexN le 15/01/2008 14:57:57

Quelques remarques sur ton code http://www.phpcs.com/codes/ENUM-JAVA-LIKE-TYPAGE-FORT_45420.aspx :

- Ton code suppose que chaque enum dispose au moins d'une méthode. Ce qui est faux. (moyen)
- Ton système dit d'énumération rend le code des méthodes internes dépendant de la position des éléments dans la table elements - voir isWeekEnd. (grave)
- d'autre part, tu me parles de contrôle de type. Mais dans ton cas, comment peut on mettre autre chose qu'une valeur du tableau. (genre $a->sunday->isWeekEnd() est complètement impossible). Quel est l'intérêt du contrôle de type dans ce cas ?
- Le code n'est plus fonctionnel si on tente une telle affectation (grave)

Je corrige ton code en ajoutant un accesseur __getContent() à la propriété content (tu as déclaré une propriété inaccessible)

Maintenant tu vois deux choses :

- Avec ma méthode, il faut 1 ligne de code pour déclarer et utiliser une énumération, toi il en faut une vingtaine.
- Si on décide de changer l'ordre des éléments dans l'énumération. Il faut modifier ton code de isWeekEnd. Le mien continue de fonctionner.


<?php
$joursDeLaSemaine = array("lundi"=>0, "mardi"=>1, "mercredi"=>2, "jeudi"=>3, "vendredi"=>4, "samedi"=>5, "dimanche"=>6);

function isWeekEnd($jour) {
global $joursDeLaSemaine;
if (!in_array($jour, $joursDeLaSemaine)) throw new Exception ("Erreur de type"); // Controle de type inutile, la fonction peut s'executer sans et retournera  un résultat correct
return (in_array($jour, array($joursDeLaSemaine["samedi"], $joursDeLaSemaine["dimanche"])));
}

$jour = $joursDeLaSemaine["lundi"];
echo "lundi est le we : ".(isWeekEnd($jour) ? "oui" : "non")."<br/>";

try {
$jour = 75;
echo "75 est le we : ".(isWeekEnd($jour) ? "oui" : "non")."<br/>";
} catch (Exception $e) {
echo "75 est le we : ".$e->getMessage()."<br/>";
}

$jour = $joursDeLaSemaine["dimanche"];
echo "dimanche est le we : ".(isWeekEnd($jour) ? "oui" : "non")."<br/>";

class EnumException extends Exception{}

class Enum {

public function __construct(){
$array=func_get_args();
$this->className=$className=$array[0];
$contentClass=$array[1];
$this->element=array();
$count=count($array);
eval('class '.$className.' extends Enum {
public function __construct($i=0, $string=\'\') {
if (self::$nbr>='.$count.') {
throw new EnumException(\'On ne peut declarer un nouvel element dans un enum !\');
}
$this->content=$i;
$this->toString=$string;
self::$nbr++;
}
public function __getContent() {
return $this->content;
}
public function __toString(){
return $this->toString;
}
'.$contentClass.'
private $content;
private static $nbr=2;
private $toString;
}
');
for ($i=2;$i<$count;$i++) {
$this->element[$i]=new $className($i-2, $array[$i]);
$this->$array[$i]=&$this->element[$i];
}
}
private $element;

public function isWeekEnd() {
return (in_array($this->__getContent(), array($this->element[5], $this->element[6])));
}
}

$a=new Enum('Day', '', 'lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 'samedi', 'dimanche');

echo "lundi est le we : ".($a->lundi->isWeekEnd() ? "oui" : "non")."<br/>";
echo "dimanche est le we : ".($a->dimanche->isWeekEnd() ? "oui" : "non")."<br/>";
//echo $a->dimanche->content;
try {
echo "sunday est le we : ".($a->sunday->isWeekEnd() ? "oui" : "non")."<br/>";
} catch (Exception $e) {
echo "sunday est le we : ".$e->getMessage()."<br/>";
}
?>

Je continue a rester convaincu que toute énumération ne nécessite pas l'utilisation d'une classe (comme utiliser un objet Integer pour faire un indice de boucle, ça frise le ridicule).

Alors non, ta solution est moins satisfaisante que celle de Malalam.

Commentaire de coucou747 le 15/01/2008 19:35:43

if (!in_array($jour, $joursDeLaSemaine)) throw new Exception ("Erreur de type");

t'appelles ca une erreur de type ???

$a=new Enum(
'Days',
'public function isWeekEnd(){ return in_array($this->toString, array(\'samedi\', \'dimanche\')); } ',
'lundi', 'mardi', 'mercredi', 'jeudi', 'samedi', 'dimanche');


echo $a->samedi.' est le weekend ? '.($a->samedi->isWeekEnd()?'oui':'non');


avec ma classe, en tapant c, t'obtiens un enum qui :



- n'a pas besoin d'avoir au moins une methode, il suffit de mettre le second argument a ''
- n'a pas besoin de la position des elements pour coder isweekend
- permet d'etre sur qu'il s'agit bien d'un element de l'enum en faisant simpleent instanceof Days
- Le code n'est plus fonctionnel si on tente une telle affectation (ce qui est un comportement NORMAL en java ou Cpp ou sql...)

Commentaire de AlexN le 15/01/2008 21:46:57

if (!in_array($jour, $joursDeLaSemaine)) throw new Exception ("Erreur de type");

>> t'appelles ca une erreur de type ???

Oui dans la mesure où une partie du contrôle est déjà faite de manière implicite (je sais que c'est un entier). Il ne me reste plus qu'à contrôler qu'il est bien dans les valeurs du tableau. Mais ce test est inutile, parce que seule l'instruction in_array($jour, array($joursDeLaSemaine["samedi"], $joursDeLaSemaine["dimanche"])) est vraiment utile pour déterminer l'appartenance ou non de la valeur testée.


$a=new Enum(
'Days',
'public function isWeekEnd(){ return in_array($this->toString, array(\'samedi\', \'dimanche\')); } ',
'lundi', 'mardi', 'mercredi', 'jeudi', 'samedi', 'dimanche');

Comme ça c'est mieux. Cela fait donc une cinquième solution.

Commentaire de coucou747 le 16/01/2008 02:56:28

la cinquieme solution c'est EXACTEMENT celle de ma source... mais adaptee a ce cas...
ma solution est la seule qui apporte un typage correct... toi tu bosses sur des tables de hashage et des int...
avec ta fonction :
function isWeekEnd($jour) {
global $joursDeLaSemaine;
...
echo isWeekEnd(0);
ca thow rien du tout... donc t'as aucune verification de typage, 0 c'est pas un jour de la semaine...

Commentaire de AlexN le 16/01/2008 08:01:51

Faudrait sortir de ton église l'intégriste...
MA SOLUTION EST LA SOLUTION. (lol)
Heureusement pour les gens un peu ouvert comme moi, en programmation, il n'existe jamais une seule solution mais plusieurs. Chacune répondant au problème d'une manière différente et apportant son lot d'avantages et d'inconvénients. Les paradigmes de programmation ne sont pas des dogmes (c'est pas comme les bouquins religieux, tout ce qui est écrit dedans n'est pas à prendre au pied de la lettre), juste des approches différentes.

Commentaire de coucou747 le 21/01/2008 14:05:46

si t'argumentes pas plus...

tu confonds une table de hashage et un enum, desole, mais dans aucun paradigme c'est correct...

parmi toutes les facons de penser un programme, aucune ne te dit de tout confondre de facon degeulasse...

table de hashage et enum c'est pas pareil... par contre en java, enum et class c'est proche :)

Commentaire de FrancoisHill le 03/11/2008 15:17:07

Bonjour à tous.
Article (et commentaires) intéressants, soulignant un point qui me tarraude de plus en plus, l'absence de typage (et donc de contrôle et robustesse) en PHP.

Pour l'instant, voici le palliatif que je propose, certes pê un tantinet compliqué pour un simple script écrit dans le langage que PHP était, mais pas choquant dans le langage que PHP veut être.




Commentaire de FrancoisHill le 03/11/2008 15:18:40

<?php
//################################################################################################
//# NAME     :
//# PROJECT  :
//# OBJECT   : Classes to define types and enforce them.
//#
//# AUTHOR   : François Hill (FH dot Spam at free dot fr)
//# DATE     : 03/11/2008
//# DESCR.   :
//# COMMENTS :
//# STATUS   : Operational
//# =============================================================================================
//# Version  : 1.0
//# Date     :
//# Author   : F.Hill
//# Object   : Creation
//# Descr.   :
//# Comments :
//#
//# =============================================================================================
//# NOTES :
//#
//# =============================================================================================
//# CODING STYLE :
//#
//# =============================================================================================
//# TODO :
//#
//################################################################################################

ini_set('display_errors'        , 'on')  ;
ini_set('log_errors'            , 'on')  ;
ini_set('error_log'             , 'on');
error_reporting(E_ALL);



// ############################################################################
// EXCEPTIONS
// ############################################################################

class FHI_PHP_LIB__Object_Of_Type__Exception             extends Exception{};

class FHI_PHP_LIB__Object_Of_Type__Wrong_Type__Exception extends Exception
{ private $myMessage="Wrong Type. Trying to assign value of wrong type.";
  
  public function __construct($msg='')
  {
    if (!empty($msg)) $msg="\n".$msg;
    parent :: __construct($this->myMessage.$msg);
  }
}


// ############################################################################
// FRAME CLASSES
// ############################################################################

/**
* Parent class for all objects with type enforcement (=validation etc.)
*
* @used   By
* @author François Hill
* @todo  
* @since  version  - 03/11/2008
* @see    Unit tested : no.
* @see    Status      : functional.
*/
abstract class Object_Of_Type
{
  //===========================================================================
  // ATTRIBUTES                                                                
  //===========================================================================

  // -----------------------------------------------------------------------------
  // Settings
  // -----------------------------------------------------------------------------

  // -----------------------------------------------------------------------------
  // Internal
  // -----------------------------------------------------------------------------

  /**
   * The actual value, wrapped by the object.
   */
  protected $value       =null;

  /**
   * To be redefined in child class
   *
   * -Unfortunatley cannot be declared as static since the static value seems to be
   * retained by the parent class even if abstract, hence would entail same value for all
   * child classes.
   */
  protected $defaultValue=null;
  

  //===========================================================================
  // METHODS
  //===========================================================================
  public function __construct($val=null)
  { echo "Called : ".__FUNCTION__." of ".__CLASS__."\n";
    
    if(is_null($val))
    { $this->value=$this->defaultValue;
    }
    else
    { $this->set($val);
    }
  }
  
  // Validate that $val is of good type
  // Needs to be defined by child class
  abstract protected function validateValue($val);
  
  // Set
  public function set($val)
  {
    if($this->validateValue($val))
    { echo "setting Value to : $val\n";
      $this->value=$val;
    }
    else
    { $msg="Use one of these values :";
      throw new FHI_PHP_LIB__Object_Of_Type__Wrong_Type__Exception($msg);
    }
  }

  // Return $value;
  public function val()
  { return $this->value;
  }
  
  /**
   * Try casting $value
   */
  public function __toString()
  {
    return (string) $this->value;
  }


}



/**
* Parent class for all objects with type based on enumeration.
*
* @used   By
* @author François Hill
* @todo  
* @since  version  - 03/11/2008
* @see    Unit tested : no.
* @see    Status      : functional.
*/
abstract class Object_Of_Type_Enum extends Object_Of_Type
{
  /**
   * Array of possible values.
   *
   * -To be redefined by child.
   * -Protected so as to not be externally writable
   * -Unfortunatley cannot be declared as static since the static value seems to be
   * retained by the parent class even if abstract, hence would entail same value for all
   * child classes.
   */
  protected $possibleValues=array();
  
  /**
   * Get function, possibleValues being protected.
   *
   * -Since $possibleValues cannot be static, this function cannot either.
   */
  public final function getPossibleValues()
  { return $this->possibleValues;
  }

  

  /**
   * Validate that $val is of good type.
   *
   * @param   mixed                $val                 Value to assign to object.
   * @return                                            True if successfully assigned,
   *                                                    false otherwise.
   */
  protected function validateValue($val)
  { echo "possibleValues=".print_r($this->possibleValues, 1)."\n";
    if (in_array($val,$this->possibleValues))
    { echo "value $val has been validated\n";
      return true;
    }
    else
    { echo "value $val has been rejected\n";
      return false;
    }
  }

  /**
   *
   */
  public function __toString()
  { #echo "using __toString()\n";

    //Find constant defined that matches the :
    $reflect         = new ReflectionClass(get_class($this));
    $constants       = $reflect->getConstants();
    $constant_flipped=array_flip($constants);

    // Catch failure
    if (!isset($constant_flipped[$this->value]))
    { return (string) $this->value;
    }
    else
    { return (string)$constant_flipped[$this->value];
    }
  }


}


// ############################################################################
// CONCRETE EXAMPLES OF DEFINED TYPES :
// ############################################################################


/**
* Definition of the 'CARD' type. (an enum type)
*
* Possible values are defined as constants and then tied to $this->possibleValues.
* The actual values of the constants are irrelevant though should all be different.
* If types are defined as strings, it is then possible to perform
* this type of verification :
*   $card=new Object_Of_Type_Card();
*   if ($card==Object_Of_Type_Card::DIAMONDS) ...
* instead of
*   if ($card->val()==Object_Of_Type_Card::DIAMONDS) ...
* TODO : think about riskyness of encouraging such a way to compare
*        If constants are not strings, could lead to unpredictable results

* @used   By
* @author François Hill
* @todo  
* @since  version  - 03/11/2008
* @see    Unit tested : no.
* @see    Status      : functional.
*/
class Object_Of_Type_Card extends Object_Of_Type_Enum
{
  // DEFINE VALUES AS CONSTANTS HERE:
  const DIAMONDS ='DIAMONDS';
  const HEARTS   ='HEARTS'  ;
  const CLUBS    ='CLUBS'   ;
  const SPADES   ='SPADES'  ;


  #// To redefine possibleValues in child class :

  #// It does not seem possible to redefine a static property
  #// that would be accessible in the parent class through self::possibleValues.
  #// Indeed self::possibleValues accesses the parent's value.
  #// All the while $this->possibleValues called in the parent class accesses the correct
  #// (child) value.
  #// -> Dilemma
  #//
  #// Method one : use a non static property
  #// Advantages :
  #// -since it's readily accessible in the parent class no setting in the constructor
  #//  required -> more concise
  #// Drawbacks :
  #// -fragile : subject to typos !!
  #
  #public $possibleValues=array(self::DIAMONDS,
  #                             self::HEARTS,
  #                             self::SPADES,
  #                             self::CLUBS);

  #// Method two : use a static property
  #// Advantages :
  #// -more robust than the first
  #// -more conceptually satisfying
  #// Drawbacks :
  #// -less concise

  public function __construct()
  {
    // "Connect" possible values in constructor.
    // Sadly possibleValues cannot be static and/or redefined in attributes section
    // and is redefined at every instanciation of an object.
    // (TODO : see if a factory could do the trick)
    $this->possibleValues=array(self::DIAMONDS  ,
                                self::HEARTS    ,
                                self::SPADES    ,
                                self::CLUBS     ,
                                );

    // Same goes for default value :
    $this->defaultValue=self::HEARTS;

    parent::__construct();
  }
}





/**
* Definition of the 'DIGIT' type. (int from 0 to 9)
*
* Overlayer of the native integer type.
* This is NOT an enum type and is based on a validation function.
*
* @used   By
* @author François Hill
* @todo  
* @since  version  - 03/11/2008
* @see    Unit tested : no.
* @see    Status      : functional.
*/
class Object_Of_Type_Digit extends Object_Of_Type
{
  public function __construct()
  {
    $this->defaultValue=0;

    parent::__construct();
  }

  protected function validateValue($val)
  { return (0<=$val && $val <=9);
  }
}




/**
* Definition of the 'EMAIL' type. (name@domain.ext)
*
* Overlayer of the native string type.
* This is NOT an enum type and is based on a validation function.
*
* @used   By
* @author François Hill
* @todo  
* @since  version  - 03/11/2008
* @see    Unit tested : no.
* @see    Status      : functional.
*/
class Object_Of_Type_Email_Address extends Object_Of_Type
{
  
  // Return true if $val is of good type (is an email address)
  //        false otherwise
  protected function validateValue($val)
  { // TODO (use Zend Email validator for example)
    return true;
  }
}





// ############################################################################
// TESTS :
// ############################################################################

echo "\n-Creating new card\n";
$card=new Object_Of_Type_Card();

//
echo "\n-Possible values for card :\n";
echo print_r($card->getPossibleValues(), 1)."\n";    

//
echo "\n-Echoing card (uses __toString):\n";
echo $card; echo "\n";

//
echo "\n-Setting card to Object_Of_Type_Card::DIAMONDS; \n";
$card->set(Object_Of_Type_Card::DIAMONDS);
echo "echo card (uses __toString):";
echo $card; echo "\n";
echo "echo card->val():";
echo $card->val(); echo "\n";

//
echo "\n-Checking if card is instanceof Object_Of_Type_Card\n";
if ($card instanceof Object_Of_Type_Card)
  echo "card is indeed instanceof Object_Of_Type_Card\n";
else
  echo "card is NOT instanceof Object_Of_Type_Card\n";

//
echo "\n-Checking if card card->val()==Object_Of_Type_Card::DIAMONDS\n";
// Would be nice to be able to do something like
// if ($card==Object_Of_Type_Card::DIAMONDS)
if ($card->val()==Object_Of_Type_Card::DIAMONDS)
  echo "card->val() is indeed ==Object_Of_Type_Card::DIAMONDS\n";
else
  echo "card->val() is NOT ==Object_Of_Type_Card::DIAMONDS\n";

echo "\n-Checking if card card==Object_Of_Type_Card::DIAMONDS\n";
echo " (possible because of how type values are defined in Object_Of_Type_Card)\n";
if ($card==Object_Of_Type_Card::DIAMONDS)
{ echo "card is indeed ==Object_Of_Type_Card::DIAMONDS\n";
}


//
echo "\n-Setting illegal value to card : \n";
echo "Exec : card->set('NOT_A_CARD'); \n";
try
{ $card->set('NOT_A_CARD');
}
catch (Exception $e)
{ echo "Exception caught : ".$e->getMessage()."\n";
}




//
echo "\n-Creating new digit\n";
$digit=new Object_Of_Type_Digit();

//
echo "\n-Echoing digit (uses __toString):\n";
try
{ #echo $digit; echo "\n";
  // Throws error : "Object of class Object_Of_Type_Digit could not be converted to string" in
  // Apparently not catchable ??
}
catch (Exception $e)
{ echo "Exception caught : ".$e->getMessage()."\n";
}
echo "\n-Echoing digit (uses ->val()):\n";
echo $digit->val();echo "\n";


//
echo "\n-Setting digit to a legal value \n";
$digit->set(9);
echo "echo digit (uses __toString):";
echo $digit; echo "\n";
echo "echo digit->val():";
echo $digit->val(); echo "\n";

$digit->set(1);
echo "echo digit (uses __toString):";
echo $digit; echo "\n";
echo "echo digit->val():";
echo $digit->val(); echo "\n";

// Sadly this is possible : (though will later result in error since $digit
// is no longer a object.
echo "\n-Setting digit through =, bypassing set() : this underlines a safety issue.\n";
$digit=12;
echo "echo digit (uses __toString):";
echo $digit; echo "\n";


//
echo "\n-Setting illegal value to digit : \n";
echo "Exec : digit->set('NOT_A_CARD'); \n";
$digit=new Object_Of_Type_Digit();
try
{ $digit->set(12);
}
catch (Exception $e)
{ echo "Exception caught : ".$e->getMessage()."\n";
}




 Ajouter un commentaire




Nos sponsors


Sondage...

Comparez les prix

CalendriCode

Février 2010
LMMJVSD
1234567
891011121314
15161718192021
22232425262728

Consulter la suite du CalendriCode

 
Développement réalisé par Nicolas SOREL (Nix) avec l'aide de : Cyril DURAND et Emmanuel (EBArtSoft), Merci à Vincent pour ses précieux conseils.
CodeS-SourceS.com© Toute reproduction même partielle est interdite sauf accord écrit du Webmaster
CodeS-SourceS.com© est une marque déposée tous droits réservés

Google Coop CodeS-SourceS Google Coop CodeS-SourceS
Temps d'éxécution de la page : 0,156 sec (4)

Nous contacter | Annoncer sur CodeS-SourceS | Mentions légales