Jump to content
php.lv forumi

Komponenšu globalizācija


Recommended Posts

Diskusija sekojoša - parasti visur un vienmēr ir nepieciešami sistēmas-globāli objekti/mainīgie. Globāļi sucks, to mēs visi zinām.

Dependency injekcijas ir labi un jauki, taču, ne vienmēr ērti. Piemērs ir modeļi - tie ir bieži lietojami, loosely-coupled un katru reizi inicializējot to vai citu modeli barot injekcijas nav gluži tas reālākais risinājums. Piemēram, modeļu bāzes klasei vienmēr nepieciešama vismaz - a: sistēmas konfigurācija b: db links. Konfigurāciju varētu organizēt kā singletonu, taču ne vienmēr būs tikai viens konfigurācijas objekts (kā manā gadījumā). Tas pats ar DB saitēm - arī itkā varētu paplašināt kā singletonu un strādāt ar vienu instanci, bet tas līdz brīdim, kad nepieciešami >1 savienojumi ar dažādiem dsn vienlaikus. Varētu jau protams veidot vairākus singletonus, bet tas būtu nemenedžējams ārprāts. Un šis nav gluži vienīgais piemērs. Sistēmas iekšējām atkarībām un sistēmas atkarīgām bibliotēkām injekcijas ir okei, bet lietām, kuras nepieciešams bieži inicializēt manuāli tas vienkārši nav ērti.

Līdz šim esmu izlīdzējies ar dependency injekcijām un pa retam, kādam globālim. Tagad uzrakstīju singletonu-reģistru (lasīt - $objects->{name} = $objekts), kurā tiek reģistrētas vitālu komponenšu objektu references un pie nepieciešamības, piemēram, modeļos, tās tiek atgūtas no šī reģistra, tādējādi apejot vajadzību pēc dependencijām. Savukārt, lai novērstu gadījumu, kad reģistrā kaut kas trūkst, speciāls exception, kuru pēcāk var noķert un nohendlot.

 

Kādas vēl ir reālas alternatīvas - bez eksotikas, kā piemēram, glabāt references apc utml.?

Link to post
Share on other sites
  • Replies 37
  • Created
  • Last Reply

Top Posters In This Topic

Top Posters In This Topic

Singletoni tie paši globāļi vien ir.

 

DIC var papildināt, lai prot nodrošināt dependencies un nebūtu tas manuāli jādara.

 

Sākumā atbrīvo modeļus (precīzāk - entities) no dependencies, datu atlases un saglabāšanas funkcionalitāti pārnes uz mapperiem, kaut kādas kompleksas darbības ar entities - uz servisiem. Tas nodrošinās ērtu darbu ar entities, nereizējoties par dependencies, piemēram, $user = new \User. User entity ir pilnīgi vienalga, no kurienes dati tiek ņemti, vai no datubāzes, vai no kāda webservisa.

 

Core objektus, kā arī mapperus un servisus reģistrē iekš DIC.

 

// Bootstrap.php
$dic->config = $dic->share(function ($dic)
{
$cfg = new \Config;

$cfg->loadFromFile('path/to/config.php');

return $cfg;
});

// Pārējie core objekti: Request, Response, Dispatcher, Logger utt

$dic->db1 = $dic->share(function ($dic)
{
return new \Db_Mysql($dic->config->db1);
});

$dic->db2 = $dic->share(function ($dic)
{
return new \Db_Pgsql($dic->config->db2);
});

$dic->user_mapper = $dic->share(function ($dic)
{
return new \User_Mapper($dic->db1); // Vai arī citu DB konekciju, kas ir reģistrēta iekš DIC
});

// User_Controller.php
class User_Controller extends \Controller
{
private $user_mapper;

public function __construct(\User_Mapper $user_mapper)
{
 $this->user_mapper = $user_mapper;
}

public function list()
{
 $this->view->users = $this->user_mapper->getActiveUsers();
}
}

// Dispatch
// "Maģija" iekš Dic::create() ir gaužām vienkārša: ar Reflection iegūst izveidojamās klases dependencies (konstruktora parametrus) un tad tos meklē pie savām reģistrētajām dependencies.
// Ja prasītā dependency nav reģistrēta iekš DIC, tad metam exception. Kad savācam vajadzīgo, tad izveidojam prasīto objektu (hint: newInstanceArgs() f-ja).
// Un to, protams, var lietot ne tikai kontrolieriem, bet jebkuram objektam.
$controller = $dic->create('User_Controller');

$controller->list();

// Vēl viens piemērs - gribam padot otro DB konekciju (PostgreSQL) un izveidot mapperi paši + lietot config:
class User_Controller extends \Controller
{
private $db;
private $config;

public function __construct(\Db $db2, \Config $config)
{
$this->db = $db2;
$this->config = $config;
}

public function list()
{
$mapper = new \User_mapper($this->db);
}
}

Link to post
Share on other sites

Kā ar gadījumu, kad vienas funkcijas ietvaros vajag kaut kādo lietot, bet ne vienmēr. Ja padod kā dependency injection, tad tas tiek inicializēts lieki.

Piemēram:

function __construct(Log $log, Db $db){
   if ($db->lalala()){
       $log->error('lalala');
   } else {
       //...
   }
}

Tas protams ir vienkāršs gadījums, bet reāli varētu būt 3,4,5 depnedencies un gadījumi, kad neizmanto nevienu, vai tikai vienu un tad tie tiek lieki inicializēti.

Edited by codez
Link to post
Share on other sites

Kā ar gadījumu, kad vienas funkcijas ietvaros vajag kaut kādo lietot, bet ne vienmēr. Ja padod kā dependency injection, tad tas tiek inicializēts lieki.

Tas protams ir vienkāršs gadījums, bet reāli varētu būt 3,4,5 depnedencies un gadījumi, kad neizmanto nevienu, vai tikai vienu un tad tie tiek lieki inicializēti.

Also, this.

Multitons ir tas pats klašu reģistrs, ko minēju topikā, ar atšķirību, ka multitons ir tas pats singletons ar vairākām instancēm. Tas neatrisina problēmu kolekciju veidošanai.

Link to post
Share on other sites

Pimple DIC

 

Notice that the anonymous function has access to the current container instance, allowing references to other objects or parameters. As objects are only created when you get them, the order of the definitions does not matter, and there is no performance penalty.

 

Ir arī shared objects.

Link to post
Share on other sites

Nē, nezinām vis.

 

Nu nav tie globāļi ļaunums.

 

Tā saka tikai tāpēc, lai n00bi neliek visus mainīgos globālajā.

Globāļi ir ļaunums jo nav iespējams atsekot un limitēt to, kas, kur un kāpēc tur tiek glabāts, kas, kur un kāpēc to izmanto utml sīkas nianses...

Edited by F3llony
Link to post
Share on other sites

Kā ar gadījumu, kad vienas funkcijas ietvaros vajag kaut kādo lietot, bet ne vienmēr. Ja padod kā dependency injection, tad tas tiek inicializēts lieki.

 

Tavā piemērā Log klase ir pietiekoši "populārs" objekts, kas noteikti tiek lietots daudz kur. Nu inicializēts tiks šeit, nevis nākamajā klasē, kur tāpat tiks lietots, kas par to?

 

EDIT: Ja nu ļoti vajag, tad var jau padot konteineru:

function __construct(Dic $dic)
{
   if ($dic->db->lalala())
   {
       $dic->log->error('lalala');
   }
   else
   {
       //...
   }
}

Edited by Joyride
Link to post
Share on other sites

To tāpat nav iespējams izdarīt :D Kas man kā programmētājam liedz kaut ko glabāt tur kur tas nav paredzēts? Jāizmanto API? Neizmantošu. Glabāšu failiņā :D

Pēc otrās reizes, kad tev paprasīs pārrakstīt visu moduli pret doto API tā, lai tas to izmantotu tā, kā tas ir paredzēts arhitektūrā, tev vairs par "failiņiem" i domāt negribēsies. Nepārproti, es fanoju par loose-coupling, bet dažreiz kaut ko limitēt ir ne tikai vajadzīgs, bet pat nepieciešams. Kaut vai tāpēc, lai varētu izsekot "kura kretīna kods $x= true pārvērš par $x = WTFOBJEKTS?!11"...

Tu idiotu tēlo un oftopiku dzen uz pilnu slodzi, jeb tikai brīvajā laikā?

Edited by F3llony
Link to post
Share on other sites
Guest
This topic is now closed to further replies.

×
×
  • Create New...