JeuWeb - Crée ton jeu par navigateur
Question autour de l'unset - Version imprimable

+- JeuWeb - Crée ton jeu par navigateur (https://jeuweb.org)
+-- Forum : Discussions, Aide, Ressources... (https://jeuweb.org/forumdisplay.php?fid=38)
+--- Forum : Programmation, infrastructure (https://jeuweb.org/forumdisplay.php?fid=51)
+--- Sujet : Question autour de l'unset (/showthread.php?tid=4101)

Pages : 1 2


Question autour de l'unset - Ter Rowan - 17-06-2009

coucou

voilà, je me pose peut être un problème qui n en est pas un mais paranoia d'un ancien développeur C oblige, je me pose des questions sur le comportement d'unset dans des cas un peu plus lourd que la simple variable

pour éviter x requêtes unitaires, je charge dans plusieurs tableaux des "objets" de l'inventaire d'une liste de personnages. Chaque tableau correspond à un type d'accès particulier ( qu'y a t il dans ce sac ? quels sont les objets de ce type ?) que j'utilise grâce à des "foreach" (pour obtenir la liste suivant des filtres) et des "isset" (est ce que l'objet existe)

Code PHP :
<?php 
while ($res= $this->_db->Suivant() )
{
$this->_byType[ $res['obj_ext_poss_id'] ][ $res['obj_ext_type_id'] ][] =
$this->_byBag[ $res['obj_ext_poss_id'] ][ $res['obj_ext_conteneur_id' ] ][ $res['obj_position'] ] =
new
Obj( $res['obj_ext_type_id'], $res['obj_id'], $res['obj_qte'], $res['obj_taille'],
$res['obj_poids'], $res['obj_quali'], $res['obj_ext_poss_id'], $res['obj_ext_conteneur_id'], $res['obj_position']);

if (
$res['obj_id'] != NULL )
$this->_possessionsId[$res['obj_id']] = $this->_byBag[ $res['obj_ext_poss_id'] ][ $res['obj_ext_conteneur_id' ] ][ $res['obj_position'] ] ];

}

je crée donc pour un enregistrement en base un objet (new Obj) que j'attribue à deux ou trois tableaux

tout cela c'est très bien mais je développe les fonctions de suppression et là quelques inquiétudes, soucis, questions

autant je construis sans problème la requête SQL qui nettoie en base, autant j'aimerais avoir un nettoyage "élégant" de mes tableaux

prenons le cas de la suppression d'un personnage. Le personnage est identifié par $res['obj_ext_poss_id']

ce que j'aimerais faire c'est, par exemple un
Code PHP :
<?php 
unset($this->_byType[ $res['obj_ext_poss_id'] ])
qui vide de la mémoire l'ensemble des éléments :

- à savoir toutes les cas de $this->_byType[ $res['obj_ext_poss_id'] ], mais ça je pense que oui
- mais aussi les objets "obj" associés (et là je ne sais pas trop)
- mais aussi l'ensemble des cases du tableau $this->_possessionsId[$res['obj_id']] qui correspondent à des objets de ce propriétaire
- etc...

là je suis dans le cas d'un personnage complet mais j'aimerais aussi pouvoir

supprimer toutes les possessions d'un personnage d'un certain type (unset($this->_byType[ $res['obj_ext_poss_id'] ][$res['obj_ext_type_id'])

ou supprimer toutes les possessions d'un personnage contenu dans un sac
(unset($this->_byBag[ $res['obj_ext_poss_id'] ][ $res['obj_ext_conteneur_id' ] ])

voyez ce que je veut dire ?

cela marche peut être complètement, naturellement mais j'ai un doute.

je serais en C je bouclerais sur tous les éléments unitaires du plus fin au plus gros, pour tout nettoyer, mais en php est ce utile ou arrive t il à se débrouiller ?

merci de votre aide


RE: [php] question autour de l'unset - Allwise - 17-06-2009

Quand tu instancies ton objet Obj et que tu assignes son instance à tes diverses variables, le hic avec unset, naholyr en parlait d'ailleurs dans un autre topic, c'est que quand tu vas faire unset($tableau['xxx']['xxx']), ça va juste couper le lien entre $tableau['xxx']['xxx'] et l'objet, mais l'objet existera toujours en mémoire, probablement du fait qu'il existe d'autres références qui pointent dessus, et donc les autres variables auxquelles l'instance est liée ne bougeront pas.

Ce que tu peux faire, c'est assigner ton instance d'Obj à une variable :
Code PHP :
<?php 
$var
= new Obj();

Et passer la référence de $var à tes tableaux & co :
Code PHP :
<?php 
$tableau
['xxx']['xxx'] = &$var;
Ainsi, $tableau['xxx']['xxx'] est lié à $var qui est lié à ton instance... Si après tu fais $var=null;, ça mettra null à $tableau['xxx']['xxx'] et aux autres. Les index et les variables existeront toujours, mais elles auront null plutôt que ton objet en valeur.

En creusant dans cette piste, tu peux sûrement arriver à tes fins.


RE: [php] question autour de l'unset - Ter Rowan - 17-06-2009

merci allwise, je vais regarder cela, mais , finalement ça revient à faire "à la main" le nettoyage complet, comme je le craignais ^^

juste un point, tu as peut être détecté une cagade dans ce que j'ai fait :

en effet, je n'ai pas mis de & dans mes égalités

$this->_byType = $this->_byBag

et pas

$this->_byType = &$this->_byBag

est à dire que j'ai des clônes de mes objets ?


RE: [php] question autour de l'unset - wild-D - 17-06-2009

théoriquement PHP est sensé garder la trace des références pointant sur ton objet et quand y en a plus il fait le nettoyage tout seul... quand il considère que c'est pertinent. (je connais pas les détail du garbage collecting de php )

unset() donc normalement ne force pas la libération de la mémoire, mais la référence, le garbage collecting devant se charger du reste (pour forcer à libérer la place immédiatement $var = null). Et comme naholyr l'a dit, y a des soucis avec des références croisées ou d'autre montage, apparemment y a des référence qui sont pas correctement effacée.


RE: [php] question autour de l'unset - Allwise - 17-06-2009

Non, y a pas une copie du contenu cible en mémoire, y a toujours qu'un seul contenu en mémoire et plusieurs liens ( les variables ).
Quand tu fais $this->_byType = &$this->_byBag, _byType va pointer sur _byBag. C'est à dire que si tu modifies _byBag, _byType sera également modifié.
Si tu omets le &, _byType sera égal à _byBag, c'est à dire qu'ils pointeront tous deux vers la même adresse mémoire, et que si tu modifies _byBag, ça n'aura aucune incidence sur _byType.


RE: [php] question autour de l'unset - naholyr - 17-06-2009

(17-06-2009, 10:26 AM)Ter Rowan a écrit : $this->_byType = $this->_byBag

et pas

$this->_byType = &$this->_byBag
En PHP5, quand la partie droite de l'affectation est un objet, c'est strictement équivalent (affectation par référence automatique).

PHP ne videra jamais la mémoire tant qu'il reste une référence à un objet, quand bien même elle ne devrait plus être active.

Exemple classique des références croisées :
Code PHP :
<?php 
class Inventaire {
protected
$proprietaire;
public function
__construct(Personnage $proprietaire) {
$this->proprietaire = $proprietaire;
}
}
class
Personnage {
protected
$inventaire;
public function
__construct() {
$this->inventaire = new Inventaire($this);
}
}

// Cet objet ne sera jamais retiré de la mémoire
$perso = new Personnage();
unset(
$perso); // $perso->inventaire étant une référence vers $perso, la mémoire n'est pas récupéré.

Triste, mais inévitable. La bonne nouvelle étant que la mémoire est bien récupérée au niveau du système après l'exécution du script, encore heureux Wink



Note : c'est encore plus flagrant si on rajoute un destructeur dans la classe Personnage ou Inventaire (avec dedans un bête echo "quelque chose"), on se rend compte que ce destructeur n'est *jamais* appelé.
Le seul moyen est d'écrire un destructeur et qu'on l'appelle manuellement. Le code suivant ne provoquera pas de fatal error :
Code PHP :
<?php 
...
class
Personnage {
...
public function
__destruct() {
unset(
$this->inventaire);
}
...

while (
true) {
$perso = new Personnage();
// unset($perso); // ne fait rien : le destructeur n'est pas appelé car il reste une référence
$perso->__destruct(); // appel forcé au destructeur, cette fois ça marche car la référence qui restait est supprimée.
}

Comme ça vous avez les exemples concrets sous les yeux Wink


RE: [PHP] Question autour de l'unset - wild-D - 17-06-2009

Citation :En PHP5, quand la partie droite de l'affectation est un objet, c'est strictement équivalent (affectation par référence automatique).
aie non, y a une subtile différence... en fait une grosse Tongue (d'ailleurs ça m'a valu une sacrée prise de tête), les alias et les "référence" d'objet c'est pas du tout "strictement équivalent".
$o = new objet();
$io = $o;// affectation par "référence" objet
$ao = &$o; // affectation par "alias"

tu peux accéder à ton objet indistinctement par $o, $io, $ao.
pourtant si tu t'amuse à réaffecter $o, $io, ou $ao; va y avoir une grosse différence, $o et son alias $ao c'est "pareil"; par contre $io, tintin Tongue


RE: [PHP] Question autour de l'unset - naholyr - 17-06-2009

Effectivement, ça valait le coup d'être précisé j'ai commis une erreur qu'en plus je connaissais (d'autant plus impardonnable) Wink


RE: [PHP] Question autour de l'unset - Ter Rowan - 18-06-2009

ok en cas de réaffectation, mais en cas de suppression c'est le même combat ?


$o = new objet()
$io = $o
$ao = &$o



puis
unset ($io);

qu'est ce qu'il y a dans $o ? null ? l'objet ?


et si je fais
unset ($ao), il se passe quoi pour $o ?

tu me diras je pourrais tester mais au boulot je n'ai pas php ^^


en tout cas merci de votre aide


RE: [PHP] Question autour de l'unset - wild-D - 18-06-2009

y se passe rien $o reste indeme ton bel objet.

-> unset ($io);
tu unset "l'accesseur" (je suis pas sûr du terme exacte) $io enfin la réf objet; non l'objet lui-même.

-> unset($ao); ben j'avais mis de gros guillement à mon pareil; parce que si tu réaffecte l'alas sur une autre variable ou tu unset l'alias; tu casse en fait le lien entre entre l'alias et la variable au lieu d'agir sur la variable.

dans le genre tordu encore; -je viens de vérifier - si tu unset($o);
$ao et $io, t'as pas de soucis ils te donnent toujours accès à l'objet.