Jump to content
php.lv forumi

Kā aizievietot vairākus vienādus vārdus?


shurix

Recommended Posts

PDO::quote. Kā jau teicu, PDO iespējams izmantot pierastā veidā, izmantojot rakstzīmju virkņu apvienošanu.

 

Uz ātro:

 

function get_tree($language) {
   $language = $this->db->quote($language);

   $stm = $this->db->query("
  	 SELECT
  		 node.*,
  		 names.name,
  		 names.url_name
  	 FROM
  		 $this->tree_table as node
  	 left join $this->names_table as names on names.tree_id = node.id and names.language_code = $language
  	 order by
  		 names.name
   ");
   return $stm->fetchAll(PDO::FETCH_ASSOC);
}

 

Tā ir objekta metode, atbilstoši kodā:

 

try {
   $tree_items = $tree->get_tree('lv');
} catch (Exception $e) {
   echo($e->getMessage());
   exit;
}

Protams tas ir vienkāršots piemērs, reāli tur ir mazliet savādāks vaicājums, rekursija utt.

Link to comment
Share on other sites

  • Replies 33
  • Created
  • Last Reply

Top Posters In This Topic

Top Posters In This Topic

Tad jautājums, kādi ir tavi apsvērumi, lai nebūvētu savu custom db klasi, neatkarīgi vai uz PDO, vai mysqli bāzes?

Plusi būtu: vari izveidot klāt Singleton vai citu paternu instan(ces/ču) iegūšanai, automātisku parametru eskeipošanu, dažādas papildus funkcijas dažādas formas datu atgriešanai, iebūvēt query log-u un kļūdu log-u.

 

Respektīvi, tas, kāpēc es iebilstu pret PS, ir tāpēc, ka uzskatu, ka custom klasi jātaisa ir tā vai tā, lai automatizēdu dažadas ar db saistītas darbības un ievēroty DRY principu. Un no tā izriet, ka, ja tiek taisīta sava db klase, tad labāk izmantot ir parastos statement-us un padot tiem parametrus automātiski eskeipojot, nekā PS, jo otrajiem ir daudz trūkumu saistība ar to, ka ir lietas, ko ar PS nav iespējams izpildīt.

Link to comment
Share on other sites

Nu apsvērumi ir tādi ka neredzu tam jēgu, vismaz salīdzinoši vienkāršām mājas lapām. Kā jau teicu, iepriekš es taisīju savas db klases uz php, bet viņas man īpaši neko vairāk nedarīja par to, ko dara PDO objekts. Es nekad netaisīju, tādu lietu, kā masīva automātiska atpazīšana, atkodēšana, lai automātiski saģenerētos in() parametrs MySql vaicājumā, vai līdzīgas lietas. Es uzskatu ka db klasei vajag nodarboties ar datubāzes un vaicājumu lietām, nevis datu struktūru atšifrēšanu vai līdzīgām lietām. Pārlieka universālu lietu taisīšana ar php noved pie veiktspējas zuduma. Jā, es esmu taisījis tādas lietas kā metodes, kas masīvus izmanto kā parametrus, piemēram, kas ievieto vai labo kādu ierakstu kā parametrus norādot tabulas nosaukumu, masīvu ar koloniņām=>datiem un where nosacījumu, bet tā jau ir pavisam cita metode, kas paredzēta tieši tādai datu apstrādei un, kas izmanto vienu no query metodēm.

 

Vaicājumu logošana jau būtībā ir salīdzinoši atsevišķs gadījums, to patiešām ir jātaisa ar atsevišķu klasi, ja to vajag. Ar ko tiks realizēts savienojums un manipulācijas ar datubāzi, tā jau ir izstrādātāja izvēle, šeit nekādi tas neatšķiras vai apakšā izmanto mysql, mysqli vai PDO, jo jebkurā gadījumā logošana būs vien jāraksta pašam.

 

Kļūdu logošana ir pavisam cits. Tās es gan netaisītu datubāzes klasēs automātiski. Agrāk taisīju, bet pēc tam es atteicos no šīs domas. Visu kļūdu logošanu taisu ar atsevišķu, tieši tam paredzētu php klasi. Iemesls ir vienkāršs, nav jēgas taisīt logošanu vairākās vietās atsevišķi, ja to var sataisīt vienā vietā.

Vieglāk to parādīt uz piemēra. Jāņem vērā ka izmantoju exceptions. Piemēram, man ir db klase, vai paša rakstīta, vai PDO nav būtiski. Tad vēl man ir lietotāja klase user, kas izmanto šo db klasi, lai lietotāju informāciju iegūtu vai ievietotu datubāzē. Tātad, pieņemsim ka man ir automātiska kļūdu logošanās db klasē un lietotāju klasē, tad pseidokods varētu būt apmēram tāds.

 

DB:

 

make query;
if error {
  log_error;
  throw exception;
} else
  return result;

 

User:

 

try {
  db->query("select..."); //Pārbaudam lietotāju, izpildot vaicājumu.
  if logged_in
 	return true;
  else
 	return false;
} catch
  return false; //Nav jālogo, jo tas izdarīts db klasē, bet vienmēr to jāpatur prātā.
}

 

Pašā kodā:

 

if user->loged_in
  public part;
else
  show "you are not logged in" message; //Nekas nav jālogo, jo tas tiek izdarīts automātiski klasēs.

 

Šeit ir stipri vienkāršots piemērs. Reālajā situācijā lietotāja klasē varētu būt sarežģītākas metodes, piemēram lietotāja ievietošana, kura kā parametru saņem masīvu ar ievadāmā lietotāja datiem. Šajā gadījumā ir jēga logos ierakstīt ne tikai db kļūdas, bet, piemēram, ir jāpārbauda un jāieraksta kļūda, ja masīva vietā tika padots pavisam kaut kas cits, teiksim cipars vai string, tātad jāveic ievaddatu pārbaude. Šajā gadījumā jau rodas nepieciešamība domāt kādas lietas jālogo un kādas lietas jau ir ierakstītas logos ar citām klasēm, ko izmanto user klase.

 

Protams tam visam izsekot līdzi ir salīdzinoši vienkārši, bet izmēģinot citu pieeju nonācu pie secinājuma ka lietas paliek vienkāršākas, vismaz man, ja klasēs pie visām pārbaudēm un kļūdām nevis logo visu pēc kārtas un domā, kas ir jau logos ierakstīts un kas nav, bet tā vietā izmet exceptionu. Šajā gadījumā logošana vienmēr notiek pašā augstākajā līmenī, kam tiek izmantota log klase, saglabājot visus datus par exceptionu. Tātad iepriekšējais piemērs:

 

DB:

 

make query;
if error {
  throw exception; //šeit nav nepieciešams rakstīt logu, jo tas tiks izdarīts pārtverot exceptionu.
} else
  return result;

 

User:

 

check_input_data;
if wrong_input_data
  throw exception("wrong input data.");
check_login_with_query; //Nevajaga izmest atsevišķi exception ja query nenostrādā, jo tas tiks izdarīts db klasē, to arī ir jāpatur prātā.
if login_correct
  return true;
else
  return false; //Te varētu arī izmest exception ar atbilstošu paziņojumu un atbilstošu kodu, kogu parasti glabāju kā klases konstanti.

 

Pašā kodā:

 

try {
  if (user->check_login($login, $password))
 	redirect to public part;
  else
 	show "wrong login" message.
catch (Exception $e) {
  $log->write("Login check error.", $e);
  show "page is not working temporary" message.
}

 

Vai arī, ja tika izmests exception pie nepareiza lietotāja vārda vai paroles.

 

try {
  user->check_login($login, $password);
  redirect to public part;
catch (Exception $e) {
  $log->write("Login check error.", $e);

  if ($e->getCode == user::E_CODE_WRONG_LOGIN)
 	show "wrong login" message.
  else
 	show "page is not working temporary" message.
}

 

Jā, koda ir vairāk ārpus klasēm, jo noteikti jāizmanto try - catch, bet toties klases paliek tīras, kas dara tikai savu darbu un neko lieku. Šeit protams zināma līdzība ar logošanu katrā klasē ir, jo arī jāpatur prātā, ka db klasē jau tiks izmests exceptions un tāpēc nav jādomā par vaicājuma pareizību user klasē un nav jāizmet tieši vaicājuma exeptions. Kaut arī ja izmestu nekas nenotiktu, koda izpilde apstātos pie pirmā izmestā exceptiona, tātad nav iespēja ka logā atkārtoti ierakstīsies divas reizes viens un tas pats, pat ja, tā teikt kļūdaini, tiktu izmesti vairāk exceptioni nekā vajag, logs paliek tīrs.

 

Būtībā šāda pieeja nesamazina koda daudzumu kopēji, arī ir jāseko līdzi tam kādā klasē kādi exceptions jau tika izmesti, bet lielākā priekšrocība ir tajā, ka saglabājās klašu loģika, katra klase dara to, kam viņa ir paredzēta. Tas ir, datubāzes klase darbojas tikai ar datubāzi un vaicājumiem, viņa nav logošanas klase, viņa nav dažādu datustruktūru atšifrētājs, viņa saņem datus vaicājumiem un izpilda vaicājumus, ja kaut kas nesanāk ziņo par radušos kļūdu, izmentot exceptionu, lietotāja klase nodarbojas ar lietotāja datiem, saņem lietotāja datus, pārbauda tos un apstrādā lietotāja datus datubāzē, izmantojot db klasi, padodot datus vajadzīgā formā, vai paziņo par kļudu, izmetot exceptionu. Vai to exceptionu ir jāielogo vai jāizvada kļūdu paziņojums jādomā ārpus klases, ja izmanto MVC, to visloģiskāk darīt kontrolierī, kas arī tieši paredzēts visas loģikas apvienošanai.

 

Tādu pieeju būtībā ir jāizmēģina, kā jau teicu, izmēģināju, man iepatikās, jo iepriekš veidojot tādas lielas klases kas dara visu, nu ne visu, bet daudz ko, īsti nesanāca tikt skaidrībā un nonākt pie pareizā secinājuma ko tieši un kur likt logos, tieši ar logiem darbojoties es nonācu līdz exceptionu izmantošanai. Ar tiem ir daudz vienkāršāk, nevajag domāt kur ko izmest, vienkārši, ir kļūda izmet exceptionu un tad pašā kodā to apstrādā, pārtver ar try - catch neatkarīgi no tā cik dziļi tas tika izmests. Tad, ar vienkāršu log metodes izaukšanu, var ierakstīt visu informāciju par exceptionu, ieskaitot stackTrace, tādā veidā pa soļiem redzot kas tika izpildīts kodā, kādos failos un kādās rindiņās kas tika izasukts un līdz ar to precīzi nonākt līdz kļudai. Kļūdu logošanai izmantoju globālu klasi, kas veic ne tikai exception kļūdu logošanu, tā var logot gan dažādas kļūdas, jebkādas, gan pilnīgi jebkuru citu informāciju ko ir jāielogo.

 

 

Tieši pašus prepared statements es pats arī neizmantoju, tas redzams metodē get_tree, ko iepriekš rādīju. Te mums domas ir vienādas, uz doto brīdi viņiem ir pārāk daudz trūkumu, pie sarežģītu vaicājumu veidošanas. Kā jau teicu PDO izmantoju tāpēc, ka tas ļauj man neveidot savu klasi, jo manējā db klase darītu ne vairāk kā to dara PDO, pat mazāk. Automātiskās eskeipošanas man patiešām nav, kaut kad agrāk arī domāju par šādām lietām, bet rezultātā nonācu līdz secinājumam ka īpaši tas daudz neko nedod, tikai sarežģī db klasi un vēl nedod Tev kontroli pār eskipošanu, kad to nevajag, uz sitien ne visai labs piemērs, bet kaut vai NULL, ko nevajag eskeipot. Protams to visu var realizēt ar dažādiem nosacījumiem, vai taisot atsevišķu metodi, kas neveic eskeipošanu utt., vai vajag, tas ir pavisam cits jautājums.

 

 

Te jau mazliet netēma aizgāja, bet visumā būtu interesanti dzirdēt citu domas ko liek vai neliek php veidotajās klasēs, tā teikt pieredzes apmaiņai un laikam jau labāk atsevišķā tēmā.

Edited by Maris-S
Link to comment
Share on other sites

Pirmo reizi redzu tik sakarīgu un g-a-r-u postu forumā. Nezinu cik tas ir pareizi, bet izklausās labi.

 

Mana loģika ir pavisam vienkārša un viegli izstāstāma. Tātad, metodēm ir jābūt un tām ir jābūt pēc iespējas mazak funkcionālām. Tas nozīme, ka lai panāktu vienu lietu ir jāizmanto, piemēram, piecas metodes. Nevis tā, ka viss ir salikts vienā, tūkstoš-rindiņas garā metodē. Ieguvums? Re-usability un, protams, KISS princips.

Link to comment
Share on other sites

Maris-S, šķiet, ka mums ir diezgan pretējas filzofijas, kā darīt lietas.

Man viens no primāriem principiem ir DRY (Do not Repeat Yourself) princips.

Tas nozīmē, ka pēc iespējas mazāk atkārtot to, kas jau rakstīts citur.

Tavā gadījumā sanāk katrā kontrolerī rakstīt logošanas funkciju. Kas nozīmē, ka desmitiem reižu atkārtot vienu un to pašu algoritmu (kodu). Diemžēl man šāda pieeja neapmierina. Man primārais mērķis ir programmēt tā, lai doma, kas radusies galvā, tiktu realizēt kodā dažās vai pat vienā koda rindiņā.

Man ir paša izstrādāt ietvars, kurš pamatā visas nepieciešamās darbības veic automātiski un cik vien tas iespējams izmanot Lazy evaluation principu, kas nozīmē, ka vajadzīgā vērtība tiek inicializēta vai aprēķināta tikai tad, kad tas ir nepieciešams.

 

Piemēram, pieņemsim, ka ir lietotājs un viņam ir virtuāli priekšmeti, nospiežot pogu atverās dialogs, kurā ar ajax ielādē šī lietotāja virtuālos priekšmetus.

Ajax izsauc url-u /ajax/user/getItems

Šādā gadījumā man servera pusē user ajax kontroliera klasē nāktos pievienot sekojošu kodu:

 

function getItems(){
  if ($uid=Auth::id()){
echo DB::q('SELECT * FROM users_items WHERE uid=%s',$uid)->getRows('json');
  }
}

 

Jā, tieši tik īsi, lasāmi es uzrakstīšu to, kas man bija nepieciešams - to algorimu, kuru šijā brīdi izdomāju un, kura man nav, bet viss pārējie algoritmi, kurus jau esmu rakstījis, ja būs vajadzīgi, izpildīsies automātiski.

Auth izsauks autorizācijas klasi, kura tiks ielādēta ar autoload handleri un id() metode nolasīs kūkijus un atgriezīs ielogotā lietotāja id.

DB izsauks db klasi ar autoload handlera palīdzību un notiks konekcija ar db serveri (šeit svarīg ir Lazy evaluation princips, jo gadījumos, kad netiek izsaukta DB klase, nenotiek ne DB klases ielāde, ne konekcija ar datubāzi), tālāk q metode izspildīs kveriju automātiski eskeipojot parametrus un atgriezīs result objektu, kura metode getRows atgriezīs visas rindas, šijā gadījumā ar parametru 'json', tas notiks json formā, ko es uzreiz varu ar echo izvadīt. Pie tam, klientu pusē izsauc šo pieprasījumu ajax post mainīgajiem tiks pievienot token mainīgais (protams automātiski), kurš savukārt servera pusē automātiski tiks pārbaudīts, lai izvairītos no XSRF uzbrukumiem. Tāpat tiks logoti kveriji un developer režīmā es pat momentāli redzēšu kverijus, to datus un pārējo, kas nepieciešam ērtai debugošanai, citā logā.

 

Man galējais mērķis ir panākt, lai es varu programmēt, nevis kodēt.

Edited by codez
Link to comment
Share on other sites

Nē, katrā kontrolierī nav vajadzības rakstīt logošanas funkciju, tā ir globāla klase, tā pat kā db. Kontrolierī jāizsauc logošanas metode, kur to vajag. To pašu echo arī jāizsauc ne vienu vien reizi, bet nekas, kods nepaliek nelasāms no tā. Nesapratu tikai kāpēc jāraksta lietotāju datu iegūšanai kodā atsevišķa funkcija un vēl ar vaicājumu, bet nu tas tā, iespējams kā piemēru domāji.

 

Piemērs logošanai.

 

require('lib/global.php');
$db = new db($connect_options);
$user = new user($db);
$log = new $log('log/a_user.log');

try {
   if ($user->is_logged_in())
  	 echo(json_encode($user->get_items()));
   else
  	 $log->write("User items requested while not logged in.");
} catch (Exception $e) {
   $log->write("Couldn't get user date.", $e);
}

Tā kā tiek izmantoti exceptions, logā ierakstīsies visa informācija, neatkarīgi no tā vai exceptions tika izmests user vai db klasē. Kā redzams logošainai nekāds kods netiek pārrakstīts no jauna, logošana tiek veikta manuāli un tieši kur to vajag, gan kļūdu paziņojumiem, gan jebkādiem citiem informatīviem paziņojumiem. Nekas un nekur netiek atkārtots.

 

Koda saīsināšana vienā rindiņā nepadara to lasāmu un pārskatāmu, tieši otrādi, lasāmība samazinās.

 

Ja nepatīk mainīgo inicializēšana, tad to pašu ko pierakstīju var saīsināt līdz class::method stilam, tikai īpašu jēgu tam neredzu.

 

Tokena piesaiste Tev tā saprotu arī notiek automātiski visur kur vajag un kur nevajag. Te atkal ar automatizāciju Tu panāc to, ko apraksti ka negribi darīt, t.i. izpildīt lieku kodu. Tātad, ja Tokens nav nepieciešams viņš vienalga būs.

 

Bet nu katram programmētājam ir savs pieejas stils, tā ke šeit nav tāda pieņēmuma kā pareizi vai nepareizi, kā kurš pieradis tā arī kodēs, ja protams nekodē komandā, tur nāktos vienoties par kādu konkrētu stilu.

 

Vienīgi, Tavā pieejā, es nesaprotu, kā tiek realizēta logošana. Tev ir sataisīta logošanas klase, ko db klase manto, vai vienkārši db klasē ir logošanas funkcijas sataisītas? Kā, piemēram, Tu veidotu klases, kurām vajadzētu izmantot gan db klasi, gan kurās būtu iespējamas ne ar vaicājumiem saistītas kļūdas, kuras arī būtu jālogo? Kā arī vēl nesapratu, kur un kā tiek norādīti db savienošanās parametri? Sanāk db klasē tos izsauc no globālās konfigurācijas mainīgiem, vai glabājas pa tiešo klasē?

Link to comment
Share on other sites

Nē, katrā kontrolierī nav vajadzības rakstīt logošanas funkciju, tā ir globāla klase, tā pat kā db. Kontrolierī jāizsauc logošanas metode, kur to vajag.

To arī domāju, ka tu katrā kontrolerī vienu vai vairākas reizes izsauc logošanās funkcionalitāti, kamēr es uzsaktu, ka tā ir smaga DRY principa pārkāpšana, jo n-tjaos kontroleros tev atkārtosies vieni un tie paši logošanās metožu izsaukumi.

 

To pašu echo arī jāizsauc ne vienu vien reizi, bet nekas, kods nepaliek nelasāms no tā.

 

Nesapratu tikai kāpēc jāraksta lietotāju datu iegūšanai kodā atsevišķa funkcija un vēl ar vaicājumu, bet nu tas tā, iespējams kā piemēru domāji.

Ja tu domā Auth::id(), tad tā neiegūst lietotāja datus, bet gan iegūst ielogojušā lietotāja id. Ja neviens lietotājs nav ielogojies atgriež 0 līdz ar to if nosacījums neizpildās. Ar if ($uid=LAuth::id) es vienlaikus pārbaudu vai lietotājs ir ielogojies un iegūstu viņa id, tāpat šajā brīdi sistēma negriežas pie db, jo sesijas neglabājas db, bet operatīvajā. Šāds risinājums ir tāpēc, ka ļoti daudzos gadījumies ir nepieciešams tikai ielogotā lietotāja id un optimizēts tā, lai to var iegūt, negriežoties pie db.

 

Piemērs logošanai.

 

require('lib/global.php');
$db = new db($connect_options);
$user = new user($db);
$log = new $log('log/a_user.log');

try {
   if ($user->is_logged_in())
       echo(json_encode($user->get_items()));
   else
       $log->write("User items requested while not logged in.");
} catch (Exception $e) {
   $log->write("Couldn't get user date.", $e);
}

Tā kā tiek izmantoti exceptions, logā ierakstīsies visa informācija, neatkarīgi no tā vai exceptions tika izmests user vai db klasē. Kā redzams logošainai nekāds kods netiek pārrakstīts no jauna, logošana tiek veikta manuāli un tieši kur to vajag, gan kļūdu paziņojumiem, gan jebkādiem citiem informatīviem paziņojumiem. Nekas un nekur netiek atkārtots.

 

Bet mana koda 3 rindiņas, izdara to pašu, ko tava koda 12 rindiņas. Kāpēc lieki jākodē?

Pie tam par atkārtošanos tu nedaudz samelojies. Tūlīt tev būs nākošais kontroleris, kurā jāpārbauda vai lietotājs ir ielogojies un tu atkal rakstīsi kļūdu apstrādi un kļūdu logošanu šādi, atkārtojot to, ko jau vienreiz rakstīji:

 


try {
   if ($user->is_logged_in()){
//citas lietas
}
} catch (Exception $e) {
   $log->write("Couldn't get user date.", $e);
}

 

Koda saīsināšana vienā rindiņā nepadara to lasāmu un pārskatāmu, tieši otrādi, lasāmība samazinās.

Tici man, ja kods netiek speciāli vai netīšām obfuscēts, tad īsaks kods, it sevisķi 4-5x īsāks kods, ir daudz lasāmāks, uzturāmāks, ātrāk uzrakstāms, ātrāk maināms un uzlabojams.

 

Ja nepatīk mainīgo inicializēšana, tad to pašu ko pierakstīju var saīsināt līdz class::method stilam, tikai īpašu jēgu tam neredzu.

Es jau teicu, mūsu filozofijas atšķirās.

Kāpēc kaut ko rakstīt, ja var nerakstīt?

Kāpēc 50 reizes atkārtot vienu un to pašu inicializācijas izsaukšanas kodu?

Vēl vairāk, teiksim, ja kontroleris ir nedaudz sarežģītāks un tā izpildes laikā vienreiz vajag izmantot 1 no 10, citreiz 10 no 10 nepieciešamajām klasēm. Ja tu veiksi katru reizi manuālu inicializāciju, tad tev vienmēr tiks veiktas visu 10 objektu inicializācijas, kamēr pēc principa Lazy evaluation , tiks inicializētas tikai tās klases, kuras reāli izmantos - tādā veidā kods ne tikai būs vieglāk rakstām, jo tev nebūs jāuztruačas, vai to klasi jau inicializēji vai nē, bet arī ātrāks, jo inicializēs tikai to, ka nepieciešams.

Pat jau manis dotajā piemērā, ja lietotājs nav ielogojies un Auth::id() atgriež 0, DB klases netiek izsaukta, tā netiek pat ielādēta un netiek veikta lieka, nevajadzīga konekcija ar datubāzi.

Lūk kur slēpjas DRY un Lazy evaluation maģija.

 

Tokena piesaiste Tev tā saprotu arī notiek automātiski visur kur vajag un kur nevajag. Te atkal ar automatizāciju Tu panāc to, ko apraksti ka negribi darīt, t.i. izpildīt lieku kodu. Tātad, ja Tokens nav nepieciešams viņš vienalga būs.

Ja man tokenu nevajadzētu visur, es noteikti radītu automātiski vai vismaz deklaratīvu veidu, kā to iedalīt.

konkrēti XSRF token gadījumā tas ir vajadzīg pilnīgi visos ajax requestos, lai nebūt iespējam XSRF ievainojamība.

 

 

Bet nu katram programmētājam ir savs pieejas stils, tā ke šeit nav tāda pieņēmuma kā pareizi vai nepareizi, kā kurš pieradis tā arī kodēs, ja protams nekodē komandā, tur nāktos vienoties par kādu konkrētu stilu.

 

Vienīgi, Tavā pieejā, es nesaprotu, kā tiek realizēta logošana. Tev ir sataisīta logošanas klase, ko db klase manto, vai vienkārši db klasē ir logošanas funkcijas sataisītas? Kā, piemēram, Tu veidotu klases, kurām vajadzētu izmantot gan db klasi, gan kurās būtu iespējamas ne ar vaicājumiem saistītas kļūdas, kuras arī būtu jālogo? Kā arī vēl nesapratu, kur un kā tiek norādīti db savienošanās parametri? Sanāk db klasē tos izsauc no globālās konfigurācijas mainīgiem, vai glabājas pa tiešo klasē?

Lieta ir pavisam vienkārša, es izmantoju autoload handleri un singleton paternu. Tātad autoload handlera ideja ir tāda, ka ja tu griezies pie klases un šī klase nav definēta, tad viņš izsau šo handleri ar parametru klases vārdu. Pēc klases vārda es atrodu to failu, kur glavājas klase un inklūdoju. Tālāk, izsaucot klases funkciju tiek automātiski izveidota klases instance, bet tikai gadījumā, ja tāda jau nav izveidota. Tas nozīmē, ka kodā (stipri vienkāršot variants, lai uztvertu domu):

 

//DB:

class DB{
 function query($query){
$instance=self::getInstance();
Log::write('You just called query: '.$query);
return new DBResult($instance->query($query));
 }
}

//Log:
class Log{
 function write($txt){
$instance=self::getInstance();
$instance->write($txt);
 }
}

//kontrolerī
class AjaxController_Index extends AjaxController{
 function hi(){
if (DB::query('SELECT * FROM users')->getRows()){
	       Log::write('Logged from hi');
}  
 }
}

 

 

Sākumā izpilde sākas ar kontrolera action-u hi(). Pirmā tiek izsaukta DB klase, ja tāda nav, tad autload handleris to ielāde, izsaucot query funkciju, kurā tiek izsaukta statiskā instance metode, kura, ja vēl nav db instance to izveito un piekonektē, ja instance jau ir, tad atgriež to. Tālāk tiek izsaukta Log klases, tur notiek tieši tas pats, tiek izveidota instance, ja tās nav. Tālāk iziet no DB::query metodet pārbauda vai dati ir atgriezti un ir ok, tiek izsaukta Log::write funkcija vēlreiz. Šoreiz klase netiek lādēta, jo tā jau ir, tāpec arī $instance::Log::getInstance() atgriež jau pirms tam uztaisītu instanci.

Kā redzams šāda pieeja ideāli nodrošina lazy loading un lazy evaluation principu, kas nozīmē, ka klases tiks ielādētas tikai tad, ja tisk izmantotas un tās tiks inicializētas tikai tad, ja tās kodā tiks izmantotas un man nav jāuztraucas, vai koda sākumā es esmu iekļāvis kādu klasi, vai esmu to inicializējis.

Edited by codez
Link to comment
Share on other sites

Es tik varu piebilst, ka ir gadiijumi, kad nav veerts izmantot singleton pattern'u un vieglaak ir izmantot vienkaarshi statisku klasi. Es parasti izdomaaju vai vajadzees chain'ot metodes - ja jaa tad singleton, ja nee, tad parasta statiska klase. Protams ir citi nosaciijumi ar, bet tie retaak izmantoti...

Link to comment
Share on other sites

To arī domāju, ka tu katrā kontrolerī vienu vai vairākas reizes izsauc logošanās funkcionalitāti, kamēr es uzsaktu, ka tā ir smaga DRY principa pārkāpšana, jo n-tjaos kontroleros tev atkārtosies vieni un tie paši logošanās metožu izsaukumi.

 

Tieši tādām lietām arī ir domātas funkcijas un metodes, lai izsauktu atkārtojamu kodu vairākas reizes to nepārrakstot, citādi jēga no funkcijām nebūtu. Kādā veidā tad sarakstīt logos dažādas neatkarīgas lietas, kas ir ārpus klases funkcionalitātes?

 

Arī programmētājs, kas pirmo reizi skatīsies uz Tavu kodu sapratīs kas notiek un nevajadzēs pētīt visas klases pēc kārtas, lai saprastu kas un kur tajās izpildās automātiski. Manā skatījumā laba koda lasāmība nav īsāks vai garāks kods, bet informatīvāks kods, nu un protams viegli uztverams.

 

Ja nu patiešām nepatīk pie katra exceptiona, kas tiek izmests, rakstīt $log->write(), tad tik pat labi var uzrakstīt exeption handleri, kas to darīs automātiski.

 

Jebkurā gadījumā logošana lietojumā vajadzīga arī ārpus klasēm un būs jāizmanto klase, kas to dara ārpusē, ne tikai konkrētos objektos. Rakstīt savu db klasi un atteikties no PDO tikai tāpēc, lai tajā būtu iekļauta logošana, ko var veikt ārpusē, neredzu jēgu.

 

Ja tu domā Auth::id()

 

Nē, es domāju tieši šo:

 

DB::q('SELECT * FROM users_items WHERE uid=%s',$uid)

 

Ko es biju aizstājis ar:

 

$user->get_items()

 

ko protams var aizstāt ar klase::metode pieeju, ja vajag un ja nepatīk inicializēt mainīgos. Bet varbūt es pārāk stipri aizraujos ar objektiem un dažas ar lietotāju saistītas darbības jāiznes ārpus lietotāja klases. :)

 

Bet mana koda 3 rindiņas, izdara to pašu, ko tava koda 12 rindiņas. Kāpēc lieki jākodē?

Pie tam par atkārtošanos tu nedaudz samelojies. Tūlīt tev būs nākošais kontroleris, kurā jāpārbauda vai lietotājs ir ielogojies un tu atkal rakstīsi kļūdu apstrādi un kļūdu logošanu šādi, atkārtojot to, ko jau vienreiz rakstīji:

 

Nu nav tā, pirmkārt jau tās 3 rindiņas neizdara tik daudz cik manējās 12. Tev būtu vēl jāiekļauj, vismaz, __autoload() un datubāzes savienojuma parametri, inicializācijai kaut kur jānotiek, lai kā viņa sataisīta. Kā jau teicu, ja slinkums lieku reizi pierakstīt $log->write(), tad to pašu var izdarīt exception handlerī un reāli no 12 rindiņām paliek:

 

if ($user->is_logged_in())
echo(json_encode($user->get_items()));

 

Kāpēc 50 reizes atkārtot vienu un to pašu inicializācijas izsaukšanas kodu?

Vēl vairāk, teiksim, ja kontroleris ir nedaudz sarežģītāks un tā izpildes laikā vienreiz vajag izmantot 1 no 10, citreiz 10 no 10 nepieciešamajām klasēm. Ja tu veiksi katru reizi manuālu inicializāciju, tad tev vienmēr tiks veiktas visu 10 objektu inicializācijas

 

Kāpēc to jādara 50 reizes? Ja tiek izmantots PDO neviens jau neliedz inicializāciju veikt savā stilā to vienu reizi, lai arī kur viņa atrastos. Inicializācijai jābūt vienalga, kaut vai __autoload, db savienojuma parametri utt.

 

Es arī nekur neteicu ka singleton nav vispār jāizmanto. Kā jau pats saki priekš kam rakstīt lieku kodu? Ja vajag singleton patterna pieeju kopā ar PDO, tad priekš kam ir jāpārraksta vesela php klase? Tā pat varētu realizēt tikai tieši singleton patterna daļu.

 

class singletonDB extends PDO {
....
....
....
} 

 

Es jau nekur nesaku ka to visu nav jāzimanto, es tikai saku priekš kam pārrakstīt db klasi, ja tāda jau ir?

 

Protams Tavā gadījumā daudz svādāk, jo datubāzes klasē Tu izveido arī citas papildus darbības, ne tikai logošanu. Tomēr man izskatījās ka tēmas autors jautā pēc kaut kā daudz vienkāršāka, nekā sarežģītas klases, kas ir veidota balstoties uz vesela ietvara struktūru. Kāpēc lai viņam neieteikt papētīt ko ļauj jau esošās php lietas izdarīt?

 

Jā un arī mysqli ļauj veidot prepared statements, var apskatīties mysqli_prepare.

Edited by Maris-S
Link to comment
Share on other sites

Nu nav tā, pirmkārt jau tās 3 rindiņas neizdara tik daudz cik manējās 12. Tev būtu vēl jāiekļauj, vismaz, __autoload() un datubāzes savienojuma parametri, inicializācijai kaut kur jānotiek, lai kā viņa sataisīta. Kā jau teicu, ja slinkums lieku reizi pierakstīt $log->write(), tad to pašu var izdarīt exception handlerī

atvaino, bet autoload handleris man jau uzrakstīts, datubāzes savienojuma parametri man jau ir uzrakstīti, inicializācija notiek automātiski tieši pie pirmās griezšanās pie klases. Ir run par to, ka es esmu jau izveidojis ietvaru, kurā strādāju un tagad, kad man vajag uzrakstīt jaunu funkcionalitāti web aplikācijai es to izdaru mazāk rindiņās kā tu to dari vadoties pēc savas izstrādes pieejas.

 

un reāli no 12 rindiņām paliek:

if ($user->is_logged_in())
echo(json_encode($user->get_items()));

Atvaino, bet, kur ir definēts tavs $user objekts?

Kā tavs user objekts piekonektējas db?

Kurā brīdī un kas inicializē datubāzi?

+ Ja tev exceptionus neapstrādās catch statments, kā tu atgriezīsi lietotājiem kļūdas paziņojumu, jo apstrādājot tos ar handleri tu varēsi tikai to ielogot, bet programmas izpilde tiks neatgriezenski pārtraukta.

 

Kāpēc to jādara 50 reizes? Ja tiek izmantots PDO neviens jau neliedz inicializāciju veikt savā stilā to vienu reizi, lai arī kur viņa atrastos. Inicializācijai jābūt vienalga, kaut vai __autoload, db savienojuma parametri utt.

Kur tad tu veiksi to inicializācijas izsaukšanu? Katra kontrolera sākumā izsauksi db inicializāciju? rakstīsi 50x?

Izsauksi vienmēr, arī tad, kad kontroleris neizmanto DB?

 

Manā gadījumā inicializācija notiek tieši tad, kad es izsaucu DB.

Ši rindiņa arī izsauc db inicializāciju

DB::query('...');

 

Šī rindiņa izsauc log klases inicializāciju

Log::write('...');

 

Respektīvi katra klase tiek ielādēta un inicializēta tajā brīdī, kas kontrolerī tiek pirmo reizi izmantota (šo jau es atkārtoju 5 reizi, bet šķiet, ka tu vēl nesaproti).

 

 

 

Es arī nekur neteicu ka singleton nav vispār jāizmanto. Kā jau pats saki priekš kam rakstīt lieku kodu? Ja vajag singleton patterna pieeju kopā ar PDO, tad priekš kam ir jāpārraksta vesela php klase? Tā pat varētu realizēt tikai tieši singleton patterna daļu.

 

class singletonDB extends PDO {
....
....
....
} 

 

Nu re, beidzot tu piekriti, ka ir jēga ekstendot esošās klases funkcionalitāti vismaz vienā aspektā.

Ja tu labi iedziļinātos sapratīsi, ka arī vairāku metožu esošo DB klašu gan PDO, gan mysqli funkcionalitāti ir vērts uzlabot - tikai tāpēc, lai neatkārtotos.

 

 

Protams Tavā gadījumā daudz svādāk, jo datubāzes klasē Tu izveido arī citas papildus darbības, ne tikai logošanu. Tomēr man izskatījās ka tēmas autors jautā pēc kaut kā daudz vienkāršāka, nekā sarežģītas klases, kas ir veidota balstoties uz vesela ietvara struktūru. Kāpēc lai viņam neiteik papētīt ko ļauj jau esošās php lietas izdarīt?

Labāk jau no paša sākuma ir apgūt labākos programmēšanas patternus, nevis vēlāk čakarēties ar pāriešanu, jo nevar izdarīt tad vienu lietu, tad otru.

 

Jā un arī mysqli ļauj veidot prepared statements var apskatīties mysqli_prepare.

Pag, neiesim otreiz to pašu apli, mēs jau noskaidrojām, ka PS (vienalga vai PDO, vai Mysqli) nespēj realizēt virkni esošu ikdienišķu kveriju, tāpēc to kā bugainu jāatmet jau sākumā.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...

×
×
  • Create New...