Super-obiect loader folosit in clasele mostenite [rezolvat]

PEAR, Smarty, ADOdb, OOP, PHP 5, XML, UML, Şabloane de proiectare, PHP-GTK.

Moderatori: coditza, Emil, Moderatori

danielsen
Average Member
Mesaje: 143
Membru din: Sâm Feb 14, 2004 12:00 am
Localitate: Cluj-Napoca
Contact:

Super-obiect loader folosit in clasele mostenite [rezolvat]

Mesajde danielsen » Dum Noi 08, 2015 7:45 pm

Am o problema tot legata de acest subiect. De catva timp am incercat sa fac un CMS simplu cu o clasa Loader in care incarc clasa pt lucru cu DB, clasa pt limba (fisiere traduceri), clasa URI (pt slug-uri) care functioneaza si ca routing, clasa Model, si asa mai departe. Problema e ca vreau ca toate clasele _model care mostenesc clasa Model parinte sa mosteneasca proprietatile si obiectele din Loader. Asta nu merge.

Arata cam asa:

Cod: Selectaţi tot

class Loader {
...
public function autoloader()
{
   // load DB class
   $this->core('DB');
   // load Lang class
   $this->core('Lang', $this);
   // load URI class
   $this->core('URI', $this);
   // load Model class
   $this->core('Model', $this);
       ...
         // DUPA ASTA FAC INSTANTIEREA CLASELOR Nume_model COPII CARE MOSTENESC CLASA PARINTE Model IN FUNCTIE DE CONTROLLERUL IN CARE MA AFLU
        ...
}

// core class loader
public function core($class, $param = NULL, $extraParam = NULL)
{
   // if class name is empty, there's nothing to do
   if (empty($class))
   {
      return $this;
   }
   // check if first parameter is an array and run this function recursively
   if (is_array($class) && count($class) > 0)
   {
      foreach ($class as $key => $val)
      {
         is_int($key) ? $this->core($val, $param, $extraParam) : $this->core($key, $param, $extraParam);
      }
      return $this;
   }
   // prepare class object name
   $object = strtolower($class);
   
   // is the class already loaded?
   if (isset($this->$object))
   {
      return $this;
   }
   // does the file exist?
   if (!file_exists(SYSTEM_PATH . 'core/' . $object . '.php'))
   {
      return $this;
   }
   // set the class name and include file
   if (class_exists($class, FALSE) === FALSE)
   {
      require_once SYSTEM_PATH . 'core/' . $object . '.php';
   }
   // instantiate class
   if (!empty($extraParam))
   {
      $this->$object = new $class($param, $extraParam);
   }
   elseif (!empty($param))
   {
      $this->$object = new $class($param);
   }
   else
   {
      $this->$object = new $class();
   }

   return $this;
}
...
}


Practic pentru clasele Core cum ar fi Model, atribui o variabila locala (ex $this->$object) atunci cand le instantiez, asa incat, dupa ce am intantiat clasa DB, si am obiectul $this->db, el va fi valabil in Lang, URI, in Model, la fel cum si obiectul $this->lang va putea fi folosit in URI, si obiectul $this->uri in Model.
Clasa Model (si oricare din celelalte clase core) au constructorul asa:

Cod: Selectaţi tot

class Model
{
   // -------------------------------------------
   // Class constructor
   // -------------------------------------------
   public function __construct(&$array = array())
   {
      // assign all the class objects that were instantiated
      // by the loader class to local class variables
      if (!empty($array))
      {
         foreach ($array as $var => $class)
         {
            $this->$var = $array->$var;
         }
      }
      
      var_dump($this); // imi afiseaza toate proprietatile si obiectele din Loader, ceea ce e bine
   }
   ...
}


Dar problema e cand am o clasa gen Page_model care mosteneste clasa parinte Model.

Cod: Selectaţi tot

class Page_model extends Model
{
   // -------------------------------------------
   // Class constructor
   // -------------------------------------------
   public function __construct()
   {
      parent::__construct();
      
      var_dump($this); // aici nu imi mai da toate proprietatile din Model
   }
}


Am nevoie de un super-obiect cu toate proprietatile din Loader, cu toate sub-modelele, asa incat sa le pot folosi in clasele mostenite (ca-i _controller sau _model). Codeigniter rezolva problema asta f.fain, dar eu as prefera sa rezolv problema asta in Loader. Daca imi poate cineva da o sugestie...
Ultima oară modificat Lun Noi 09, 2015 10:38 pm de către danielsen, modificat 1 dată în total.



emanu31
PHPRomania Supporter
Mesaje: 27
Membru din: Mar Sep 02, 2014 11:55 am

Re: Super-obiect loader folosit in clasele mostenite

Mesajde emanu31 » Lun Noi 09, 2015 12:46 pm

1.

Cod: Selectaţi tot

$this->$var = $array->$var;

$array este de tip array, dar dupa il folosesti ca si obiect, nu iti da nicio eroare aici?

2.

Cod: Selectaţi tot

$this->$object = new $class();

Nu am testat, dar cred ca ar trebui sa folosesti ceva de genul Singleton pentru Model, altfel mereu o sa ai o instanta noua.

danielsen
Average Member
Mesaje: 143
Membru din: Sâm Feb 14, 2004 12:00 am
Localitate: Cluj-Napoca
Contact:

Re: Super-obiect loader folosit in clasele mostenite

Mesajde danielsen » Lun Noi 09, 2015 10:35 pm

emanu31 scrie:1.

Cod: Selectaţi tot

$this->$var = $array->$var;

$array este de tip array, dar dupa il folosesti ca si obiect, nu iti da nicio eroare aici?

2.

Cod: Selectaţi tot

$this->$object = new $class();

Nu am testat, dar cred ca ar trebui sa folosesti ceva de genul Singleton pentru Model, altfel mereu o sa ai o instanta noua.


Ai dreptate, nu fac treaba asa, e array si nu-l pot folosi, dar am rezolvat altfel cu o clasa CMS in care setez __set() si __get() si o incarc inainte de toate clasele, si folosesc un obiect care il setez ca parametru in constructori la toate clasele importante pe care le extind in clasele mostenite si merge f.bine asa. Am luat modelul asta http://www.phpro.org/tutorials/Model-Vi ... r-MVC.html si mi se pare f.bun pt ce am nevoie. Mai putin ca in casele mostenite trebuie sa folosesc totdeauna obiectul $this->cms->nume_clasa->functie si ma enerveaza, dar pana gasesc o alta solutie, e bine ca imi merge si nu am nevoie mereu de instantieri.

nevvermind
Senior Member
Mesaje: 1264
Membru din: Mar Iun 22, 2010 3:17 pm

Re: Super-obiect loader folosit in clasele mostenite [rezolv

Mesajde nevvermind » Mar Noi 10, 2015 3:40 am

Omu, fii modern.
Ce vrei tu sa faci se numeste "dependency injection".
Mai specific - si in stadiul initial - ai vrut sa faci "contructor injection", dar te-ai lovit de faptul ca un copil trebuie sa ofere si dependintele parintelui, nu numai ale lui.
Acum faci de fapt "setter injection", prin __set().

Dar jista cateva probleme; unele mai mici, altele mai mari:
- __set este chemat numai daca proprietatea nu este accesibila; vei avea wtf-uri cand vei declara un "protected $member" si vei face "$class->member";
- sunt anti-setteri, fiindca poti schimba starea obiectului mai tarziu (deci obiectul debine "mutable"), spre deosebire de ctor injection, unde poti ascunde foarte bine proprietatile, ele fiind setate numai prima data (immutable);
- nu-i o idee buna sa impui arhitectura modelelor; nu numai ca tu impui o arhitectura anume (prin nevoia de a sub-clasa Model), dar oferi tot felul de colaboratori mai mult sau mai putin necesari (nu orice model lucreaza cu DB, traduce sau foloseste URI-uri); modelele trebuie lasate la libera alegere: daca vrei un simplu obiect, sa poti face asta, fara a extinde Model, si fara a necesita o conexiune la DB; imagineaza-ti ca trebuie sa testezi asa ceva. Cam dificil.
- daca pasezi un array, nu te poti folosi de "type hinting" sa impui un anumit tip (nu poti impune "SomeType" ca in "myMethod(SomeType $type)");
- amesteci autoloading-ul cu autowiring-ul (crearea de dependinte si injectarea lor)
- foloseste un DI container ca lumea (uite unul simplu: https://github.com/silexphp/Pimple)
- foloseste autoloading de sec 21: http://www.php-fig.org/psr/psr-4/examples/
- n-ar strica sa folosesti Composer: nu numai ca-ti da un autoloader moca, dar deschide usa catre mii de alte tool-uri (gen un container DI)

Cu ocazia asta am incercat Pimple - nifty little tool: http://pastie.org/10547579
Facusi un canal de php pe freenode - ##php-ro : https://webchat.freenode.net/


Înapoi la “PHP Avansat”

Cine este conectat

Utilizatori ce ce navighează pe acest forum: Niciun utilizator înregistrat și 10 vizitatori