je suis passé un peu sur ce cours pour un petit "retour aux sources de la POO sur PHP". J'ai commencé à coder en formation de développeur avec .Net en POO et j'ai toujours bossé comme ça. J'ai commencé puis survolé le cours et je dois avouer qu'il y a des choses qui me choquent beaucoup :
Déjà je trouve que l’intégralité du cours essais d’allé trop loin mais trop vite ! Je pense effectivement que le cours devrait être réparti en deux grandes lignes POO Base et POO avancé, par contre chaque partie devrait être plus fournie.
Déjà les namespaces je trouve ça fou de ne pas en parler rapidement.
Exemple :
J’ai un site avec un objet Article défini d’une façon et un site avec un Article défini autrement, j’ai besoin de joindre mes deux codes des sites. Je pourrais imaginer utiliser des objets \Site1\Article et Site2\Article (si j’ai bien renseigné les dépendances et chemin nécessaire bien sûr). Alors que si je n’ai pas de namespace l’Article du site1 est le même que l’Article du site2 pour mon code.
De plus il me semble que dans l’activité finale il y a des namespace.
Pour tous les framework il y a des namespaces, je sais que ce n’est pas un cours sur ça mais quand même.
La récupération de données dans le Manager, je ne suis pas du tout d’accord avec ça.
Les données sont récupérées dans le DAO qui normalement est (quand on fonctionne en couche.) dans la couche DAL, le Manager est dans la couche BLL et l’objet dans la BO.
On peut d’ailleurs constater que pendant tout le cours le traitement et la vue prend tout (c’est quoi cet index.php qui est un fourre-tout !) alors que en début de cours on explique bien que une class un job. En fait-il manque cruellement de Controller ou de Manager pendant toute la partie cours.
Apres avec MVC (Model Vue Controller) pour le coup, on peut imaginer la partie Model prendre : L’objet + le DAO. Bien que la partie DAO est géré avec un ORM le plus souvent et donc avec (par exemple) les annotations plus un extends de EntityRepository pour les requêtes complexe (doctrine par exemple).
Pour bien aider à comprendre la POO je trouve que pousser plus UML serait beaucoup mieux, ça permettrai d’avoir notamment une approche de databasefirst ou codefirst, de voir le principe de faire tout son programme ainsi que sa base sur UML et générer le code minimal. C’est aussi plus simple d’avoir une vision de l’héritage et communication entre classes/jobs.
Le pattern Singleton est surtout utilisé pour une application type connecté plus qu’un site qui exécute des scripts il me semble. (Mais dans le cas de php compilé on peut imaginer en avoir besoin.)
Le pattern Front Controller aurait pu être bien à mettre en avant, il est utilisé dans beaucoup de frameworks dont Symfony2 (il me semble).
Personnellement je pense qu’utiliser un framework maison OC pour initier des débutants à la POO ce n’est pas une bonne idée.
Je vous conseille de passer direct à symfony2 ou même ce cours :
Mais à moins d’avoir beaucoup de temps devant vous ne perdez pas de temps à apprendre à utiliser un framework que vous n’utiliserez jamais en entreprise ou même à la maison.
Créer votre framework maison quand on débute en POO, c’est super pour des étudiants ou si vous avez du temps à perdre, sinon je vous le déconseille. Je l’ai vécu, c’est glorifiant parce qu’on voit des choses diverses mais très long et en terme de rendu visible on met du temps pour pas grand-chose. Au final vous irez apprendre à utiliser un framework, car en réalité vous n’arrivez pas à en avoir un qui arrive à la cheville des grands noms utilisés dans le monde professionnel. De plus certains d’entre eux prennent du temps à maitriser donc c’est plus rapide de passer par eux directement.
Bref, pour une fois (chez OC) je suis un peu déçu de ce cours. Je dois avouer que j’en attendais beaucoup plus, peut être que je vais finir le tp final mais je ne suis pas sûr. Gérer le cache pour des pages en version framework maison à voir. Si je n’ai pas fini demain je passe à symfony2 & 3 qui m’apportera plus, j’ai jamais eu l’occasion de finir le cours (pas eu le temps) au moins ça me fera un petit rappel de reprendre tout du début. C’est dommage parce qu’il y a toujours des choses à voir et revoir (et débattre) avec la POO.
Je viens de démarrer le cours mais je me pose un certains nombre de questions, car je me retrouve avec plusieurs erreurs, et même (en dernier ressort) en copiant/collant le code fourni par le cours. Mes soucis démarrent avec la partie "Manipulation des données stockées".
En effet, j'ai suivi la "bonne pratique" qui veux qu'a chaque classe déclarée nous faisons un nouveau fichier, mais dans l'exemple du cours, dois-je faire suivre le PersonnagesManager à la suite de la Classe Personnage sur le même fichier? En ayant chaque Classe sur un fichier séparé je m'en suis sorti en rajoutant un require 'PersonnagesManager.php' sur la classe Personnage mais est-ce correct?
J'ai quand même eu une erreur en faisant le 'require', car ayant fait un var_dump de $manager->getListe(), j'ai bien mes objets, les clés du tableau sont ok, mais leurs valeurs sont égales à "nulles" et rien ne s'insère en base (j'ai mis un try catch qui affiche 'connexion ok' et je suis bien connecté à ma base). Ne faudrait-il pas rajouter ceci dans le constructeur du personnage?
public function __construct($data = []) {
$this->hydrate($data);
}
Je vous remercie pour vos réponses et éclaircissements.
Bonjour Total_Noob, je ne me souviens plus trop de tout ça j'ai donc regardé vite fait la fin de ce chapitre... Bon oui effectivement si tu crée un perso de cette manière:
De plus ta classe et le fichier on le même nom ce qui est aussi plus facile à suivre/trouver maintenir.
Exemple :
Personnage.php est la classe Personnage.
Ou
PersonnageManager.php est la classe PersonnageManager.
Normalement on les mets dans des espaces de noms. Je vous invite à voir le cours sur les espaces de noms (je crois qu’il y en a un sur OC).
Au niveau du require, à ce niveau du cours il faut le mettre systématiquement (si je ne dis pas de bêtises) après on peut utiliser un autoload pour éviter ce genre de problèmes.
Hydrater dans un constructeur doit correspondre à un besoin strict. Même si il faut instancier un objet au dernier moment normalement.
Dans mon cas, je dirais que le plus souvent ce n’est pas une bonne idée et encore plus si vous êtes amené à utiliser un framework et/ou Twig.
Un exemple tout bête, si j’utilise certain framework, je crée un objet formulaire qui utilise la structure de mon objet Personnage (par exemple).Là, je créé une vue qui va être utilisée pour éditer/créer un personnage, je me retrouve à utiliser la même vue pour deux cas d’utilisation.
Dans ma vue Twig, je passe un objet Personnage. Si je ne l’ai pas créé avant, j’aurai une erreur. Je crée un objet vide pour enfin le passer à la vue qui (après des contrôles) me permet de l’envoyer en base.
Ceci est juste un exemple il pourrait y avoir plein d’autre raison pour ne pas faire ça. Mais d’autre cas ou on en aurait besoin. Il me semble qu’hydrater dans le constructeur doit être un choix clairement défini pour autre chose que juste éviter de faire Personnage->hydrate() ;
Dans les deux cas Total_Noob et Belarif, je vous invite à regarder :
Les logs d’erreurs sur le serveur si vous en avez.
Votre version de PHP et la façon d’utiliser Pdo, personnellement j’ai une classe DBConnection qui s’occupe de tout ça et je remarque que je n’utilise pas Pdo toute à fait de la même façon.
Si vous pouvez essayer la requête directement en base sans php, histoire de toujours être sûr que la requête en elle-même ne retourne pas d’erreurs, ça serait bien aussi.
Total_Noob, il me semble qu’avec ça :
$donnees = $q->fetchAll(\PDO::FETCH_ASSOC);
Vous avez un tableau de données. Après un var_dump($donnees) peux permettre de savoir si vous avez de la data qui retour de la requête en base.
Belarif, vous pouvez faire (il me semble) :
return $q->rowCount();
après le : $q->execute();
Pour avoir le nombre de lignes affectées par la requête dans la base.
Aussi un var_dump sur $perso dans la fonction add pour être sur que l’objet est bien hydraté ou non.
Voilà, j’espère que j’ai réussi à vous aider un peu.
Osush, tout ce que tu dis est très juste cependant à leur stade ils apprennent la POO et je pense qu'il faut quand même bien maitriser la POO pour après se pencher sur le framework de leur choix. Ce cours est très bien fait, je dis qu'ils suivent ce cours comme il est fait et après ils pourront se mettre à tout ça ;-)
<?php
class Personnage{
private $_id;
private $_nom;
private $_forcePerso;
private $_degats;
private $_niveau;
private $_experience;
public function hydrate(array $donnees){
foreach($donnees as $key => $value){
$method = 'set'.ucfirst($key);
if (method_exists($this,$method)){
$this->$method($value);
}
}
}
//Getters
public function id(){
return $this->_id;
}
public function nom(){
return $this->_nom;
}
public function forcePerso(){
return $this->_forcePerso;
}
public function degats(){
return $this->_degats;
}
public function niveau(){
return $this->_niveau;
}
public function experience(){
return $this->_experience;
}
// Setters
public function setId($id){
// On convertit le nombre en entier
$id = (int)$id;
// On vérifier si le nombre est positif
if ($id > 0){
$this->_id = $id;
}
}
public function setNom($nom){
// vérifier si le nom est une chaine de caractère
if (is_string($nom)){
$this->_d = $nom;
}
}
public function setForcePerso($forcePerso){
// Convertir le nobre $forcePerso en entier
$forcePerso = (int) $forcePerso;
if (($forcePerso >= 1) && ($forcePerso <= 100)){
$this->_forcePerso = $forcePerso;
}
}
public function setDegats($degats){
// Convertir le nombre $degats en entier
$degats = (int)$degats;
// Ajouter la condition que le nombre soit compris entre 0 ET 100
if($degats >= 0 && $degats <= 100){
$this->_degats = $degats;
}
}
public function setNiveau($niveau){
// //Convertir le nombre $degats en entier
$niveau = (int) $niveau;
// Ajouter la condition que le nombre soit compris entre 1 ET 100
if ($niveau >= 1 && $niveau <= 100){
$this->_niveau = $niveau;
}
}
public function setExperience($experience){
// //Convertir le nombre $degats en entier
$experience = (int) $experience;
// Ajouter la condition que le nombre soit compris entre 1 ET 100
if ($experience >=1 && $experience <= 100){
$this->_experience = $experience;
}
}
}
class PersonnagesManager{
private $_db;
public function __construct($db){
$this->setDb($db);
}
public function add(Personnage $perso){
//préparation de la requete d'insertion
// Assignation des valeurs pour le nom, la force, les dégats, l'éxpérience et le niveau du personnage
//exécution de la requete
$q = $this->_db->prepare('INSERT INTO personnages(nom,forcePerso,degats,niveau,experience) VALUES(:nom,:forcePerso,:degats,:niveau,:experience)');
$q->bindValue(':nom', $perso->nom());
$q->bindValue(':forcePerso', $perso->forcePerso(), PDO::PARAM_INT);
$q->bindValue(':degats', $perso->degats(), PDO::PARAM_INT);
$q->bindValue(':niveau', $perso->niveau(), PDO::PARAM_INT);
$q->bindValue(':experience', $perso->experience(), PDO::PARAM_INT);
$q->execute();
}
public function delete(Personnage $perso){
//exécute une requete de type delete
$this->_db->exec('DELETE FROM personnages WHERE id = '.$perso->id());
}
public function get($id){
// exécute une requete de type SELECT
$id = (int)$id;
$q = $this->_db->query('SELECT id,nom,forcePerso,degats,niveau,experience FROM personnages WHERE id='.$id);
$donnees = $q->fetch(PDO::FETCH_ASSOC);
return new Personnage($donnees);
}
public function getList(){
// retourne la liste de tous les personnages
$persos = [];
$q = $this->_db->query('SELECT id, nom, forcePerso, degats, niveau, experience FROM personnages ORDER BY nom');
while ($donnees = $q->fetch(PDO::FETCH_ASSOC))
{
$persos[] = new Personnage($donnees);
}
return $persos;
}
public function update(Personnage $perso){
//prépare unerequete de type update
//Assignation des valeurs à la requete
// Exécution de la requete
$q = $this->_db->prepare('UPDATE personnages SET forcePerso = :forcePerso, degats = :degats, niveau = :niveau, experience = :experience WHERE id = :id');
$q->bindValue(':forcePerso', $perso->forcePerso(), PDO::PARAM_INT);
$q->bindValue(':degats', $perso->degats(), PDO::PARAM_INT);
$q->bindValue(':niveau', $perso->niveau(), PDO::PARAM_INT);
$q->bindValue(':experience', $perso->experience(), PDO::PARAM_INT);
$q->bindValue(':id', $perso->id(), PDO::PARAM_INT);
$q->execute();
}
public function setDb(PDO $db){
$this->_db = $db;
}
}
$perso = new Personnage([
'nom' => 'Victor',
'forcePerso' => 5,
'degats' => 0,
'niveau' => 1,
'experience' => 0
]);
$db = new PDO('mysql:host=localhost;dbname=personnage', 'root', '');
$manager = new PersonnagesManager($db);
$manager->add($perso);
Ma base de donnée est ; personnage. ma table, je l'ai nommée: personnages.
kid_jonath en fait je suis plutôt d'accord avec vous. Le seul bémol, c'est sur l'activité final avec le fameux 'old framework maison' de OC (il semble qu'ils sont sur Symfony2 maintenant.) qui demande aux élèves de comprendre et s'accoutumer à un framework qu'ils n'utiliseront plus après.
Ce qui me choque (c'est peut être moi qui déconne) c'est apprendre à des novices que les requête sql sont dans le manager à mon sans elles sont dans le DAO pas dans le manager.
Ensuite je pense vraiment qu'il manque au moins les espaces de noms, pour habituer les futurs développeurs objet. Ça serait bien de les mettre en place dans les objets du cours même si ils ne sont pas expliqués en détails. Au moins les évoquer et faire un lien sur le cours OC.
Belarif,
Vous n’avez pas de constructeur dans Personnage il me semble par contre vous avez :
public function hydrate(array $donnees){
foreach($donnees as $key => $value){
$method = 'set'.ucfirst($key);
if (method_exists($this,$method)){
$this->$method($value);
}
}
}
De plus vous inscrivez une valeur à 0 de l’expérience dans votre code. Vous ne faites pas d’assignation de valeur si l’expérience et >= 1 donc 0 n’est pas plus grand ou égale à 1, l’expérience n’a donc pas de valeur.
Si vous avez ce genre de problèmes un var_dump($perso) DANS la fonction add() de votre manager peut vous aider à voir si au moins vous envoyez un objet Personnage avec des valeurs.
Je suis d'accord avec toi. Mais pour ma part j'ai trouvé ce cours très enrichissant. Il est vrai qu'après on n'utilise plus ce framework. Je suis sur Silex en ce moment et je n' ai eu aucun mal à m'y habitué après ce cours.
En ce qui concerne les espaces de noms, on les utilise dans la dernière partie du cours sans trop expliquer il est vrai. Ce qui m'avait obligé à voir tout ça de mon côté.
Pour les requêtes sql c'est vrai dans silex elles sont dans le DAO et pas dans le manager mais techniquement en y regardant de plus près c'est pareil c'est juste une histoire de nom.
La dernière partie est plus difficile à prendre en main pour les débitants mais en s'accrochant c'est tout à fait réalisable et je pense que même si quelques détails changent par la suite ça forme et aide à attaquer l'apprentissage des framework par la suite ;-)
kid_jonath en fait je suis plutôt d'accord avec vous. Le seul bémol, c'est sur l'activité final avec le fameux 'old framework maison' de OC (il semble qu'ils sont sur Symfony2 maintenant.) qui demande aux élèves de comprendre et s'accoutumer à un framework qu'ils n'utiliseront plus après.
Ce qui me choque (c'est peut être moi qui déconne) c'est apprendre à des novices que les requête sql sont dans le manager à mon sans elles sont dans le DAO pas dans le manager.
Ensuite je pense vraiment qu'il manque au moins les espaces de noms, pour habituer les futurs développeurs objet. Ça serait bien de les mettre en place dans les objets du cours même si ils ne sont pas expliqués en détails. Au moins les évoquer et faire un lien sur le cours OC.
Belarif,
Vous n’avez pas de constructeur dans Personnage il me semble par contre vous avez :
public function hydrate(array $donnees){
foreach($donnees as $key => $value){
$method = 'set'.ucfirst($key);
if (method_exists($this,$method)){
$this->$method($value);
}
}
}
De plus vous inscrivez une valeur à 0 de l’expérience dans votre code. Vous ne faites pas d’assignation de valeur si l’expérience et >= 1 donc 0 n’est pas plus grand ou égale à 1, l’expérience n’a donc pas de valeur.
Si vous avez ce genre de problèmes un var_dump($perso) DANS la fonction add() de votre manager peut vous aider à voir si au moins vous envoyez un objet Personnage avec des valeurs.
oui le var_dump() est bien pratique. Plus tard avec des frameworks vous avez des outils tel que des profiler/barre de développement qui peuvent aider beaucoup plus. Pensez à faire un tour voir comment utiliser Xdebug. De plus un bon IDE est vraiment indispensable (d'après moi) pour développer en objet. Personnellement j'utilise Netbeans mais il y en a beaucoup d'autre.
Bonjour Osush et Kid_jonath, merci pour vos éclaircissements. J'avais réussi à afficher et insérer en base en mettant le constructeur, seulement, je trouve ça dommage qu'il y ai les "manques" que j'ai signalé lors de mon 1e message lorsqu'on suit le cours. Si le rédacteur du cours peux en être avisé, je pense qu'il faudrait corriger cette partie du cours (ajouter le constructeur ou lors de l'instansiation de l'objet $perso ne pas faire appel à la méthode add() mais hydrate() ) car en l'état, rien ne s'affiche (même avec le php_debug sur "on" dans mon php.ini) et rien ne s'insère en base. Et je trouve ça dommage car je trouve que des notions importantes sont apprises grace à ce TP.
Bonjour à tous , je suis sur un projet de site internet oop et à vrai dit je voudrais que ce soit du lourd.Ma question est la suivante : comment fait on pour integrer un editeur de code avec le même design que sublime text?Merci de bien vouloir me repondre.Je voudrais le code source.
- Edité par Bamba Aboulatif 22 février 2017 à 17:04:29
Je ne suis pas sur de comprendre ce que vous voulez dire quand vous parlez de l'API de réflexion.
Vous parlez de REST Client ?
Si vous parlez de l'intérêt d'une API, oui il y a beaucoup de situation ou vous allez en avoir besoin. Il y a plus de chance qu'au début vous utilisiez des API avant d'en coder vous même.
Bamba, je suis plutôt d'accord avec johan8x. Ce qu'il vous a envoyé (j'avais trouvé la même chose) est ce qui correspondait le plus à votre demande. Pour rester (plus ou moins) dans le sujet vous avez un bundle Symfony2 qui l’intègre. Si ça marche avec Symfony2, ça devrait être aussi "facilement" utilisable en Silex2.
Je ne suis pas sur de comprendre ce que vous voulez dire quand vous parlez de l'API de réflexion.
Vous parlez de REST Client ?
Si vous parlez de l'intérêt d'une API, oui il y a beaucoup de situation ou vous allez en avoir besoin. Il y a plus de chance qu'au début vous utilisiez des API avant d'en coder vous même.
Bamba, je suis plutôt d'accord avec johan8x. Ce qu'il vous a envoyé (j'avais trouvé la même chose) est ce qui correspondait le plus à votre demande. Pour rester (plus ou moins) dans le sujet vous avez un bundle Symfony2 qui l’intègre. Si ça marche avec Symfony2, ça devrait être aussi "facilement" utilisable en Silex2.
Je viens vous demandez de l'aide car je ne comprend pas pourquoi après avoir appeler la fonction get de mon manager et ranger le perso dans une variable sa ne m'affiche rien quand j'appelle $perso->nom();
Il me semble qu'il y est des problèmes d'informations dans la connexion à la base de données. Avec un var_dump() vous pouvez vous assurer que la base vous renvoi de la donnée.
Mais déjà peut être de ce coté la :
$db = new PDO('mysql:host=localhost;dbname=combats','root', '');
Personnellement je n'utilise pas çà : <?= mais plutôt <? echo $var; ?> ou <?php echo $var; ?> .
Je vous fait confiance sur le fait que ça fonctionne. Notamment sur votre version php et configuration :
Je n'en suis qu'aux prémices, là où les personnages se frappent et tout et tout , c'est-à-dire ICI mais j'ai un problème avec le code suivant :
<?php
$perso1 = new Personnage; // Un premier personnage
$perso2 = new Personnage; // Un second personnage
$perso1->setForce(10);
$perso1->setExperience(2);
$perso2->setForce(90);
$perso2->setExperience(58);
$perso1->frapper($perso2); // $perso1 frappe $perso2
$perso1->gagnerExperience(); // $perso1 gagne de l'expérience
$perso2->frapper($perso1); // $perso2 frappe $perso1
$perso2->gagnerExperience(); // $perso2 gagne de l'expérience
echo 'Le personnage 1 a ', $perso1->force(), ' de force, contrairement au personnage 2 qui a ', $perso2->force(), ' de force.<br />';
echo 'Le personnage 1 a ', $perso1->experience(), ' d\'expérience, contrairement au personnage 2 qui a ', $perso2->experience(), ' d\'expérience.<br />';
echo 'Le personnage 1 a ', $perso1->degats(), ' de dégâts, contrairement au personnage 2 qui a ', $perso2->degats(), ' de dégâts.<br />';
car j'obtiens ceci :
5050
Le personnage a de force, contrairement au personnage 1 qui a de force. 3738
Le personnage a d'expérience, contrairement au personnage 1 qui a d'expérience. 60110
Le personnage a de dégâts, contrairement au personnage 1 qui a de dégâts.
En fait, le problème est que les valeurs sont indiquées avant la publication de l'instruction ECHO. Les valeurs sont donc bien là mais au lieu de les placer dans la phrase il me les affiche avant la phrase.
Merci king-kong, là je suis sur un portable et je ne vois pas l'option "résolu". Peut-être sur un écran de PC.
J'ai un peu continué la lecture et je vais me permettre d'abuser ... au sujet de l'auto-chargemenent de classes. J'ai compris qu'il est préférable de placer chaque classe dans un fichier unique et que faire un require pour chacun d'eux est un peu laborieux mais je reste sans comprendre l'utilité de spl_autoload_register car dans l'exemple initial où on désire utiliser MaClasse.php on fait :
require'MaClasse.php';
mais l'option retenue serait :
<?php
functionchargerClasse($classe)
{
require$classe . '.php'; // On inclut la classe correspondante au paramètre passé.
}
spl_autoload_register('chargerClasse'); // On enregistre la fonction en autoload pour qu'elle soit appelée dès qu'on instanciera une classe non déclarée.
$perso=newPersonnage;
Dans cette dernière on fait quand même un require d'un archivo php. Je vois bien qu'il y a la variable $classe dont j'ignore comment elle est définie mais qui suppose la création d'une fonction... J'imagine bien qu'il y a un intérêt mais il m'échappe... Quel avantage aurait ce système par rapport au premier et surtout, comment présenter le possible chargement de différentes pages PHP si telle est la fonction?
Désolé si cette question démontre clairement des lacunes basiques de ma part, j'ai regardé sur le net au sujet de spl_autoload_register mais je n'ai rien trouvé d'assez explicite pour ma petite tête... et j'aurais aimé le comprendre dans le contexte de ce cours avant de poursuivre.
Salut, comme tu là si bien dit la classe spl_autoload_register permet de charger automatiquement des classe lorsqu'elles sont non déclarer pendant l'instanciation de celle-ci. la variable $classe représente donc cette classe qui n'est pas déclarer et dont on a instancier.
Exemple si fais un $perso = new Personnage(), la variable $class = Personnage, et ensuite la fonction spl_autoload_register se chargera charger la classe pour qu'elle soit disponible lors de l'instanciation
Bonjours a tous, je suis déjà bien avancer sur le sujet du PHP et le MySQL mais j'ai un petit problème pour la suite. Je veux que quand l'utilisateur ajouter une nouvelles pages, créer la page avec les variables et la stocker dans un endroit qui est personnelle a l'utilisateur.
SI QUELQU'UN A LA RÉPONSE JE SUIS OUVERT A TOUT SORTE D’IDÉE MERCI !!!
Tognol Charles
contact@charles-tognol.fr
Autodidacte Passionné
Tognol Charles
contact@charles-tognol.fr
Autodidacte Passionné