Fork me on GitHub

Bine ai venit

Există multă informație perimată pe Web care induce noii utilizatori PHP în eroare, propagând rele practici și cod nesigur. PHP: The Right Way este o referință rapidă și ușor de citit, pentru standarde populare de programare PHP, cu link-uri către tutoriale cu autoritate de pe web și ceea ce consideră contributorii ca sunt cele mai bune practici în prezent.

Nu există o metodă canonică (standard) de a folosi PHP. Acest website țintește să expuna noii dezvoltatori PHP unor noi subiecte, pe care poate ei nu le-ar fi descoperit decât prea târziu, și dorește să transmită profesioniștilor idei proaspete legate de acele subiecte pe care ei le-au aplicat de ani de zile fără să le mai reconsidere. Acest website nu iți va spune ce unelte să folosești, dar iți va oferi sugestii de opțiuni, explicând, când se poate, diferențele de abordare și cazurile de utilizare.

Acesta este un document “viu” și va continua să fie actualizat cu mai multe exemple și informații utile pe măsură ce ele devin disponibile.

Traduceri

PHP: The Right Way e (sau va fi curând) tradus în diferite limbi:

Cum să contribui

Ajută-ne să facem acest website cea mai bună resursă pentru noii programatori PHP! Contribuie pe GitHub

Du vestea mai departe!

PHP: The Right Way are imagini banner pe care le poți folosi pe websiteul tău. Arată-ți susținerea și ajută-i pe dezvoltatorii PHP noi să afle unde să găsească informații de calitate!

Vezi imagini banner

Back to Top

Început

Folosește versiunea stabilă curentă (5.5)

Dacă abia ai început cu PHP fii sigur că începi cu ultima versiunea stabilă de PHP 5.5. PHP a făcut mari progrese adăugând noi funcționalități în ultimii ani. Nu lăsa diferența de număr minor de versiune dintre 5.2 și 5.5 să te păcălească, ea reprezintă îmbunătățiri majore. Dacă ești în căutarea unei funcții sau a modului de utilizare a unei funcții, documentația de pe website-ul php.net va avea răspunsul.

Web Server încorporat

Poți începe să înveți PHP fără a îți face griji în privința instalării unui întreg web server. Începând cu versiunea PHP 5.4+ dezvoltatorii au inclus un server web built-in. Pentru a porni serverul execută urmatoarea comandă, din terminal, în directorul rădăcină a proiectului tău:

> php -S localhost:8000

Instalare pe Mac

OSX vine cu PHP preinstalat dar este de obicei în urmă față de ultima versiune stabilă. Lion vine cu PHP 5.3.6, Mountain Lion are 5.3.10, iar Mavericks are 5.4.17.

Pentru a actualiza PHP pe OSX îl poți obține instalat printr-un număr de managere de pachete Mac, cu php-osx by Liip fiind cel recomandat.

Cealaltă opțiune este să îl compilezi tu singur, în acest caz fii sigur că ai instalat Xcode sau substitutul de la Apple “Unelte de linie de comanda pentru Xcode” descărcabile de pe Apple’s Mac Developer Center.

Pentru un pachet complet “tot-intr-unu” incluzând PHP, Apache și MySQL, toate cu o interfață de control GUI ușor de folosit, încearcă MAMP sau XAMPP.

Instalare pe Windows

PHP e disponibil sub diferite forme pe Windows. Îl poți descărca sub formă de binare și până recent puteai folosi un instalator ‘.msi’, dar acesta nu mai e disponibil după PHP 5.3.0.

Pentru a învăța și pentru dezvoltare locală poți folosi webserver-ul încorporat în versiunea PHP 5.4+ deoarece nu ai nevoie să îl configurezi. Dacă ți-ar plăcea un “totul-inclus” care include un webserver serios și de asemenea MySQL atunci unelte precum Web Platform Installer, Zend Server CE, XAMPP şi WAMP te vor ajuta să obții rapid un mediu de dezvoltare pe Windows. Acestea fiind spuse, aceste unelte vor fi puțin diferite faţă de mediul de producție, și trebuie sa ții cont de posibile diferențe mai ales dacă lansezi codul pe o platforma GNU\Linux.

Dacă ai nevoie să rulezi sistemul de producție pe Windows atunci IIS7 iți va da cea mai mare stabilitate și cea mai bună performanță. Poți folosi phpmanager (un plugin GUI pentru IIS7) pentru a configura și administra PHP mai simplu. IIS7 vine cu FastCGI deja încorporat, ai nevoie doar să configurezi PHP ca handler. Pentru suport și resurse adiționale există o arie dedicata pe iis.net pentru PHP.

Vagrant

Rularea aplicației tale pe diferite medii în dezvoltare și producție poate duce către apariția unor bug-uri neobișnuite atunci când are loc lansarea aplicației. De asemenea este dificil sa păstrezi actualizate la zi diferite medii de dezvoltare cu aceleași versiuni ale tuturor bibliotecilor folosite atunci când se lucrează cu o echipa de dezvoltatori.

Dacă dezvolți pe Windows și lansezi pe Linux (sau orice non-Windows) sau dezvolți în echipă ar trebui să iei în calcul folosirea unei mașini virtuale. Sună complicat, dar folosind Vagrant poți construi o mașină virtuală simplă în numai câțiva pași. Aceste mașini de bază pot fi configurate manual sau poți folosi “provisioning”-software cum sunt Puppet sau Chef care să facă asta pentru tine. Inițializarea mașinii de bază e o metodă bună de a te asigura că mai multe mașini sunt setate într-o manieră identică și elimină nevoia de a avea liste cu comenzi de configurare. De asemenea iți poți distruge mașina de bază și o poți recrea fără prea mulți pași manuali fiind astfel ușor de a crea o instalare proaspătă.

Vagrant creează directoare partajate folosite pentru a păstra în comun codul tău intre gazda și mașina virtuală, însemnând ca poți crea și edita fișiere pe mașina gazda și apoi poți rula codul înauntru mașinii virtuale.

Un pic de ajutor

Dacă ai nevoie de puțin ajutor pentru a începe să folosești Vagrant există trei servicii ce ar putea fi utile:

Back to Top

Ghid stil cod

Comunitatea PHP este mare, diversă, și este compusă din nenumărate biblioteci, framework-uri și componente. Este comun ca dezvoltatorii să aleagă câteva dintre acestea și sa le combine într-un singur proiect. E important ca, codul PHP să adopte (pe cât posibil) un stil de programare comun pentru a fi ușor pentru dezvoltatori să amestece diferite biblioteci în proiectele lor.

Framework Interop Group a propus și a probat o serie de recomandări de stil. Nu toate se refera la stilul codului dar acelea care se refera sunt: PSR-0, PSR-1, PSR-2 si PSR-4. Aceste recomandări sunt doar un set de reguli pe care unele proiecte precum Drupal, Zend, Symfony, CakePHP, phpBB, AWS SDK, FuelPHP, Lithium, etc au început să le adopte. Le poți implementa în proiectele tale sau poți continua să folosești propriul tău stil personal deși nu ar fi recomandat.

Ideal ar fi să scrii cod PHP care aderă la un standard cunoscut. Aceasta ar putea fi orice combinație de PSR-uri, sau unul dintre standardele de codare făcute de PEAR sau Zend. Aceasta înseamnă că alți dezvoltatori pot citi și lucra cu codul tău cu ușurință, iar aplicațiile care implementează componente pot avea consecvență chiar și atunci când lucrează cu mult cod din terțe părți.

Poți folosi PHP_CodeSniffer pentru a verifica codul față de oricare din aceste recomandări, iar module plugin pentru editoarele de text precum Sublime Text 2 iți pot da indicii în timp real.

Folosește PHP Coding Standards Fixer al lui Fabien Potencier pentru a modifica automat sintaxa codului tău așa încât ea să se conformeze acestor standarde salvându-te pe tine de la rezolvarea fiecărei probleme manual.

Engleza este preferată pentru toate numele de simboluri și infrastructura codului. Comentariile pot fi scrise în orice limba ușor accesibilă tuturor părților ce vor lucra cu bucata de cod.

Back to Top

Puncte interesante ale limbajului

Paradigme

PHP este un limbaj flexibil, dinamic, care suportă o varietate de tehnici de programare. A evoluat dramatic peste ani, notabile fiind adăugarea solidului model orientat pe obiect în PHP 5.0 (2004), funcțiile anonime și namespace-uri în PHP 5.3 (2009), traits în PHP 5.4 (2012).

Programare orientată pe obiecte

PHP are un complet set de funcționalități orientate pe obiect incluzând suport pentru clase, clase abstracte, interfețe, moștenire, constructori, clonare, excepții, și multe altele.

Programare funcțională

PHP suporta funcții de “prima mână”, asta însemnând ca o funcție poate fi asignată unei variabile. Atât funcțiile definite de utilizator cat și cele definite de limbaj pot fi referențiate de o variabilă și invocate dinamic. Funcțiile pot fi furnizate ca argument către alte funcții (funcționalitate denumită funcții de “Înalt Nivel”) sau pot returna alte funcții.

Recursivitatea, o funcționalitate care permite unei funcții să se auto-apeleze este suportată de limbaj, dar majoritatea codului PHP se concentrează pe iterație.

Noile funcții anonime (cu suport pentru closures) sunt prezente începând cu PHP 5.3 (2009).

PHP 5.4 a adăugat abilitatea de a lega closure-uri de scope-ul obiectului și suport îmbunătățit pentru callables așa încât ele pot fi folosite interschimbabil cu funcții anonime în aproape orice caz.

Meta programare

PHP suportă diverse forme de meta-programare prin mecanisme ca Reflection API și Metode Magice. Sunt multe metode magice disponibile precum __get(), __set(), __clone(), __toString(), __invoke(), etc. care permit dezvoltatorilor să intervină în comportamentul clasei. Programatorii de Ruby spun deseori că în PHP lipsește method_missing, dar aceasta e disponibilă sub forma __call() and __callStatic().

Namespace-uri

După cum am menționat mai sus, comunitatea PHP e formată din multi dezvoltatori care creează mult cod. Asta înseamnă că într-o bibliotecă poate fi folosit același nume de clasă ca în altă bibliotecă. Când ambele biblioteci sunt folosite în același namespace ele sunt în coliziune și cauzează probleme.

Namespace-urile rezolvă această problemă. Precum e descris în manualul PHP, namespace-urile pot fi comparate cu directoarele unui sistem de operare ce conțin fișiere; doua fișiere cu același nume pot co-exista în directoare separate. De asemenea, două clase PHP cu același nume pot co-exista în namespace-uri PHP diferite. Este atât de simplu.

E important să iți bagi codul într-un namespace așa încât să poată fi folosit și de alți dezvoltatori fără frica de coliziune cu alte biblioteci.

O metodă recomandată de a folosi namespace-uri este prezentată în PSR-0, care se dorește să furnizeze o convenție standard de fișiere, clase și namespace-uri pentru a permite cod “plug-and-play”.

În Decembrie 2013 PHP-FIG a creat un nou standard pentru autoloading: PSR-4, care probabil într-o zi va înlocui PSR-0. Momentan ambele sunt folosite întrucât PSR-4 necesită PHP 5.3 iar multe proiecte 5.2 implementează PSR-0. Dacă vei folosi un standard pentru autoloading pentru o nouă aplicație sau pachet atunci aproape sigur vei vrea să te uiți spre PSR-4.

Biblioteca Standard

Biblioteca PHP Standard (SPL) este încorporată în PHP și furnizează o colecție de clase și interfețe. Este făcută în principal de clase de structuri de date (stack, queue, heap, s.a.m.d) și iteratori care pot traversa aceste structuri de date sau propriile tale clase care implementează interfețe SPL.

Interfața linie de comandă

PHP a fost creat pentru scopul primar de a scrie aplicații web, dar este de asemenea util pentru scrierea de scripturi pentru linia de comandă (CLI). Programele PHP de linie de comandă te pot ajuta să automatizezi sarcini comune precum testarea, lansarea, și administrația aplicației.

Programele PHP CLI sunt puternice pentru că poți folosi codul aplicației tale direct fără să fii nevoit să ai un GUI web pentru el. Doar fii sigur să nu pui scripturile CLI PHP în rădăcina publică.

Încearcă să rulezi PHP din linia de comanda:

> php -i

Opțiunea -i va afișa configurația ta PHP exact ca funcția phpinfo.

Opțiunea -a furnizează un shell interactiv, similar cu IRB-ul lui Ruby sau cu shell-ul interactiv al lui Python. Există o multitudine de alte opțiuni de linie de comandă utile.

Hai să scriem un simplu program CLI “Hello, $name”. Ca să îl încercăm, creăm un fișier numit hello.php, ca mai jos.

<?php
if ($argc != 2) {
    echo "Uz: php hello.php [name].\n";
    exit(1);
}
$name = $argv[1];
echo "Hello, $name\n";

PHP setează două variabile speciale bazate pe argumentele cu care este rulat scriptul tău. $argc este o variabilă integer ce conține numărul argumentelor și $argv este un array ce conține valoarea fiecărui argument. Primul argument este întotdeauna numele fișierului scriptului tău PHP, în cazul nostru hello.php.

Expresia exit() este utilizată cu un număr nenul pentru a înștiința shell-ul că comanda a eșuat. Coduri de exit des uzitate pot fi găsite aici

Ca să ne rulăm scriptul de mai sus din linia de comandă:

> php hello.php
Uz: php hello.php [name]
> php hello.php world
Hello, world

XDebug

Una dintre cele mai utile unelte în dezvoltarea de software este un debugger (depanator) bun. Acesta te lasă să urmezi execuția codului tău și să monitorizezi conținutul stivei. XDebug, debugger-ul PHP-ului, poate fi utilizat de diverse IDE-uri pentru a furniza Breakpoints (puncte de oprire) și inspecție a stivei. Poate de asemenea ajuta unelte ca PHPUnit sau KCacheGrind care analizează sau fac profilul cod-ului.

Dacă te găsești într-o situație mai grea, și deja ai încercat var_dump/print_r și tot nu ai găsit problema, poate că ai nevoie de un depanator.

Instalarea XDebug poate fi alunecoasă, dar una din cele mai importante funcționalități este “Debugging remote” - dacă dezvolți cod local și apoi îl testezi într-un mediu virtual sau pe un server, Remote Debugging este funcționalitatea pe care o vei vrea disponibilă imediat.

Tradițional, vei modifica VHost-ul din Apache sau .htaccess cu aceste valori:

php_value xdebug.remote_host=192.168.?.?
php_value xdebug.remote_port=9000

“remote host” și “remote port” vor corespunde calculatorului tău local și portul pe care a fost IDE-ul tău configurat să asculte. Apoi, e nevoie numai să iți pui IDE-ul să “asculte după conexiuni” și să apelezi adresa URL:

http://your-website.example.com/index.php?XDEBUG_SESSION_START=1

IDE-ul tău va intercepta starea curentă pe măsura ce script-ul se execută, permițându-ți să setezi breakpoints și să inspectezi valorile din memorie.

Debuggeri grafici fac foarte ușor să pășești prin cod, să inspectezi variabile, să evaluezi cod chiar în timpul rulării. Multe IDE-uri au încorporate sau suportă depanare grafică pe bază de plugin cu xdebug. MacGDBp e gratuit, open-source și de sine stătător GUI de xdebug pentru Mac.

Back to Top

Management-ul dependințelor

Există o multitudine de biblioteci PHP, framework-uri, și componente din care să alegi. Proiectul tău va folosi cel mai probabil câteva dintre acestea — acestea sunt dependințele proiectului. Pană recent PHP nu a avut o metodă bună de a administra aceste dependințe ale proiectului. Chiar dacă le administrai manual, tot trebuia să te îngrijești de autoload-eri. Nu mai e cazul.

Există două sisteme de management de pachete în PHP - Composer și PEAR. Care e mai bun? Ambele!

În general, pachetele Composer sunt disponibile numai în proiectele pe care le specifici tu explicit, pe când un pachet PEAR este disponibil pentru toate proiectele. Deși aparent PEAR sună mai ușor, există avantaje în folosirea abordării per-proiect.

Composer și Packagist

Composer este un manager genial de dependințe pentru PHP. Listezi dependințele proiectului tău în fișierul composer.json și cu câteva comenzi simple Composer va descărca automat dependințele și va seta autoloading-ingul pentru tine.

Există deja multe biblioteci PHP care sunt compatibile cu Composer, gata să fie folosite în proiectul tău. Aceste “pachete” sunt listate pe Packagist, repository-ul oficial de biblioteci PHP compatibile Composer.

Cum să instalezi Composer

Poți instala Composer local (în directorul curent; deși asta nu mai este recomandat) sau global (e.g. /usr/local/bin). Să presupunem că vrei să instalezi Composer local. Din directorul rădăcina al proiectului tău:

curl -s https://getcomposer.org/installer | php

Asta va descărca composer.phar (o arhivă PHP binară). Poți executa asta cu php pentru a administra dependințele proiectului. Nota: dacă inserezi codul descărcat direct în interpreter, citește mai întâi codul online ca să iți confirmi ca e sigur.

Cum să instalezi Composer (manual)

Instalarea manuală este o tehnică mai avansată; însă există varii motive pentru care un dezvoltator ar prefera această metodă versus folosirea interactivă. Instalarea interactivă verifică instalarea ta de PHP ca să se asigure că:

Deoarece o instalare manuală nu face nici una din aceste verificări, trebuie să decizi dacă merită pentru tine. Mai jos se arată cum obții Composer manual:

curl -s https://getcomposer.org/composer.phar -o $HOME/local/bin/composer
chmod +x $HOME/local/bin/composer

Calea $HOME/local/bin (sau alta aleasa de tine) trebuie să fie în $PATH. Asta va avea ca rezultat disponibilitatea comenzii composer.

Când dai peste documentație care cere să rulezi Composer ca php composer.phar install, poți substitui cu:

composer install

Această secțiune va presupune că ai instalat composer global.

Cum să definești și să instalezi dependințe

Composer ține seama de dependințele proiectului tău într-un fișier numit composer.json. Îl poți administra manual dacă vrei, sau poți folosi însuși Composer. Comanda composer require adaugă o dependință a proiectului iar dacă nu ai un fișier composer.json unul va fi creat. Aici e un exemplu care adaugă Twig ca dependință a proiectului.

composer require twig/twig:~1.8

Alternativ, comanda composer init te va ghida către construcția unui fișier composer.json pentru proiectul tău. Folosind oricare din medote, când ai creat composer.json îi poți spune Composer-ului să descarce și să instaleze dependințele în directorul vendors/. Asta se aplică și proiectelor pe care le-ai descărcat care deja au un fișier composer.json:

composer install

Acum, adaugă această linie în fișierul PHP principal al proiectului tău; îi va spune lui PHP să folosească autoloader-ul din Composer.

<?php
require 'vendor/autoload.php';

Acum iți poți folosi dependințele în proiect și vor fi încărcate automat când este nevoie de ele.

Actualizarea dependințelor

Composer creează un fișier numit composer.lock care stochează versiunea exactă a fiecărui pachet pe care îl descarcă când ai executat prima data php composer.phar install. Dacă împărtășești proiectul tău cu alți dezvoltatori și composer.lock este parte a distribuției tale, când ei execută php composer.phar install ei vor obține aceleași versiuni ca și tine. Pentru a iți actualiza dependințele, rulează php composer.phar update.

Acest lucru este cel mai util când iți definești necesitățile ca versiuni flexibile. De exemplu o versiune necesară de ~1.8 înseamnă “orice mai nou decât 1.8.0, dar mai jos decât 2.0.x-dev”. Poți folosi * ca în 1.8.*. Acum comanda php composer.phar update va actualiza toate dependințele către cea mai nouă versiune definită de tine.

Înștiințări de actualizare

Pentru a primi înștiințări de noi versiuni te poți înscrie în VersionEye, un serviciu web care poate monitoriza conturile tale GitHub și BitBucket după fișiere composer.json și poate trimite email-uri cu notificări legate de noile pachete lansate.

Verificarea dependințelor tale împotriva problemelor de securitate

Security Advisories Checker este un serviciu web și o unealtă de linie de comandă, ambele vor examina composer.lock și iți vor spune dacă ai nevoie să actualizezi vreuna din dependințe.

PEAR

Alt manager de pachete, veteran, apreciat de mulți programatori PHP este PEAR. Se comportă similar cu Composer, dar are niște diferențe notabile.

PEAR cere ca fiecare pachet sa aibă o structură specifică, ceea ce înseamnă că autorul pachetului trebuie să îl pregătească pentru PEAR. Folosirea unui pachet care nu a fost pregătit pentru a funcționa cu PEAR nu e posibilă.

PEAR instalează pachete global, ceea ce înseamnă că odată ce le-ai instalat ele sunt disponibile tuturor proiectelor de pe acel server. Asta poate fi bine dacă mai multe proiecte depind de același pachet cu aceeași versiune dar poate conduce la probleme dacă două proiecte au nevoie de două versiuni.

Cum să instalezi PEAR

Poți instala PEAR descarcând instalatorul phar și executându-l. Documentația PEAR are instrucțiuni de instalare detaliate pentru fiecare sistem de operare.

Dacă folosești Linux, poți căuta de asemenea în managerul de pachete al distribuției tale. Debian și Ubuntu, spre exemplu au un pachet apt php-pear.

Cum să instalezi un pachet

Dacă pachetul e listat pe lista de pachete PEAR, îl poți instala specificând numele oficial

pear install foo

Dacă pachetul este găzduit pe alt canal, ai nevoie întâi sa discover (descoperi) canalul și să îl specifici când instalezi. Vezi Folosire canale docs pentru mai multe informații despre acest topic.

Dependințe PEAR cu Composer

Dacă deja folosești Composer și ai mai vrea să instalezi și ceva cod PEAR, poți folosi Composer că să iți administreze dependințele tale PEAR. Acest exemplu va instala cod de la pear2.php.net:

{
    "repositories": [
        {
            "type": "pear",
            "url": "http://pear2.php.net"
        }
    ],
    "require": {
        "pear-pear2/PEAR2_Text_Markdown": "*",
        "pear-pear2/PEAR2_HTTP_Request": "*"
    }
}

Prima secțiune "repositories" va fi folosită pentru a îl înștiința pe Composer că trebuie sa “inițializeze” (sau “discover” in terminologie PEAR) repo-ul pear. Apoi secțiunea require va prefixa numele pachetului așa:

pear-channel/Package

Prefixul “pear” este hard-codat pentru a evita orice conflicte, pentru că dacă numele unui canal pear ar putea fi același cu un alt nume de vendor de pachete, atunci numele scurt al canalului (sau întregul URL) poate fi folosit pentru a referi în care canal este pachetul.

Când acest cod e instalat el va fi disponibil în directorul vendor și automat disponibil prin autoloader-ul Composer:

vendor/pear-pear2.php.net/PEAR2_HTTP_Request/pear2/HTTP/Request.php

Pentru a folosi acest pachet PEAR pur și simplu te referi la el așa:

$request = new pear2\HTTP\Request();

Back to Top

Practici de programare

De bază

PHP este un limbaj vast care permite programatorilor de toate nivelurile abilitatea de a produce cod nu numai în mod rapid, dar și în mod eficient. Totuși, pe parcursul avansului prin limbaj, uităm adeseori bazele pe care le-am învățat la început (sau nu) în favoarea unor scurtături și/sau unor rele obiceiuri. Pentru a combate această problemă des întâlnită, această secțiune are ca scop reamintirea programatorilor bazelor din PHP.

Date și Timp

PHP are o clasă numită DateTime pentru a te ajuta la citirea, scrierea, compararea sau calcularea unor date sau timpi. Sunt multe funcții legate de date și timp în PHP în afară de DateTime, dar ea furnizează o interfață ușoară și orientată pe obiect pentru majoritatea cazurilor. Poate manevra fusuri orare, dar asta este în afara acestei scurte introduceri.

Pentru a începe lucrul cu DateTime, transformi un string brut într-un obiect cu metoda fabrică createFromFormat() sau poți face un new \DateTime pentru a obține data și timpul curente. Folosești metoda format() pentru a transforma DateTime înapoi într-un string pentru afișare.

<?php
$raw = '22. 11. 1968';
$start = \DateTime::createFromFormat('d. m. Y', $raw);

echo 'Start date: ' . $start->format('m/d/Y') . "\n";

Calcularea cu DateTime este posibilă cu clasa DateInterval. DateTime are metode precum add() și sub() care primesc un DateInterval ca argument. Nu scrie cod care presupune același număr de secunde în fiecare zi, pentru că atât ora de iarna și alterările de fus orar vor invalida această asumpție. Folosește intervale de date pentru asta. Pentru a calcula diferența de dată folosește metoda diff(). Va returna un nou DateInterval care este super ușor de afișat.

<?php
// creează o copie a lui $start și adaugă o lună și 6 zile
$end = clone $start;
$end->add(new \DateInterval('P1M6D'));

$diff = $end->diff($start);
echo 'Diferenta: ' . $diff->format('%m month, %d days (total: %a days)') . "\n";
// Diferenta: 1 month, 6 days (total: 37 days)

Pe obiecte DateTime poți folosi comparații standard:

<?php
if ($start < $end) {
    echo "Start este inainte de sfarsit!\n";
}

Un ultim exemplu pentru a demonstra clasa DatePeriod. Este folosită pentru a itera prin evenimente recurente. Poate primi două obiecte DateTime, start și end, și intervalul pentru care va returna toate evenimentele dintre ele.

<?php
// afiseaza toate Joi-ile dintre $start and $end
$periodInterval = \DateInterval::createFromDateString('first thursday');
$periodIterator = new \DatePeriod($start, $periodInterval, $end, \DatePeriod::EXCLUDE_START_DATE);
foreach ($periodIterator as $date) {
    // afiseaza fiecare data din perioada
    echo $date->format('m/d/Y') . ' ';
}

Șabloane de proiectare

Când îți construiești aplicația e util să folosești șabloane de proiectare des folosite (design patterns) atât în codul tău cât și în structura proiectului. Folosirea acestor șabloane comun întâlnite este utilă deoarece face mult mai ușor de administrat codul și permite altor dezvoltatori să înțeleagă rapid cum se îmbina totul.

Dacă folosești un framework atunci majoritatea codului de nivel înalt cât și structura proiectului vor fi bazate pe acel framework, așa că multe din deciziile arhitectură au fost deja luate pentru tine. Dar este la latitudinea ta să alegi cele mai bune șabloane de urmat în codul pe care îl scrii deasupra framework-ului. Dacă nu folosești un framework atunci va trebui să găsești șabloanele care se potrivesc cel mai bine tipului și mărimii aplicației pe care o construiești.

Back to Top

Injectarea dependințelor

Din Wikipedia:

Injectarea dependințelor este un șablon de proiectare software care permite scoaterea dependințelor hard-codate și face posibilă schimbarea lor, fie că este în timpul compilării sau în timpul rulării.

Acest citat face ca acest concept să sune mult mai complicat decât este cu adevărat. Injectarea dependințelor pune la dispoziția unei componente propriile sale dependințe ori prin injecție în constructor, apel al metodelor sau prin setarea proprietăților. E atât de simplu.

Concept de bază

Putem demonstra conceptul cu un simplu, deși naiv exemplu.

Aici avem clasa Database care necesită un adaptor ca să vorbească cu baza de date. Instanțiem adaptorul în constructor și creăm o dependință explicită. Asta face testarea dificilă și înseamnă că clasa Database este strâns cuplată de adaptor.

<?php
namespace Database;

class Database
{
    protected $adapter;

    public function __construct()
    {
        $this->adapter = new MySqlAdapter;
    }
}

class MysqlAdapter {}

Acest cod poate fi rescris (refactored) pentru a folosi injectarea de dependințe și așadar să flexibilizeze dependința.

<?php
namespace Database;

class Database
{
    protected $adapter;

    public function __construct(MySqlAdapter $adapter)
    {
        $this->adapter = $adapter;
    }
}

class MysqlAdapter {}

Îi dam acum lui Database propria lui dependință față de atunci când îl lăsam pe el sa și-o creeze singur. Am putea chiar crea o metodă care ar accepta un argument al dependinței și ar seta-o astfel, sau dacă proprietatea $adapter ar fi publică am putea-o seta direct.

Problema Complexă

Dacă ai citit vreodată despre injectarea dependințelor atunci ai văzut probabil termenii “Inversiunea Controlului” sau “Principiul inversiunii dependinței”. Acestea sunt problemele complexe pe care injectarea dependințelor le rezolvă.

Inversiunea controlului

Inversiunea controlului, după cum și numele îi sugerează, este “inversarea controlului” unui sistem prin păstrarea controlului organizațional complet separat de obiectele noastre. În termeni de injectarea dependințelor, asta înseamnă flexibilizarea dependințelor noastre prin controlul și instanțierea lor în altă parte a sistemului.

De ani, framework-urile PHP realizau inversiunea controlului, dar, întrebarea a devenit, care parte a controlului o inversezi, și spre ce? De exemplu, framework-urile MVC puneau la dispoziție un super obiect sau controller de bază pe care alte controllere trebuia să îl extindă pentru a primi acces la dependințele sale. Aceasta este inversiune a controlului, însă, în loc de flexibilizare a dependințelor, această metodă le mută doar în altă parte.

Injectarea dependințelor ne permite să rezolvăm mai elegant această problemă prin injectarea numai a dependințelor de care avem nevoie, când avem nevoie de ele, fără a fi nevoie să le explicităm deloc în scris.

Principiul inversiunii dependințelor

Principiul inversiunii dependințelor este “D”-ul din setul S.O.L.I.D de principii de proiectare orientată pe obiecte care spune că ar trebui să “depinzi de abstracțiuni și nu de concrete”. Spus simplu, asta înseamnă că dependințele noastre ar trebui să fie interfețe/contracte sau clase abstracte mai degrabă decât implementări concrete. Putem refactoriza exemplul de mai sus ca să urmeze acest principiu.

<?php
namespace Database;

class Database
{
    protected $adapter;

    public function __construct(AdapterInterface $adapter)
    {
        $this->adapter = $adapter;
    }
}

interface AdapterInterface {}

class MysqlAdapter implements AdapterInterface {}

Exista câteva beneficii acum că clasa Database depinde de o interfață și nu de ceva concret.

Imaginează-ți că lucrezi în echipă iar colegul tău lucrează la adaptor. În primul exemplu, ar trebui să așteptăm după colegul ca să termine adaptorul înainte de a îl mock-ui pentru unit teste. Acum că dependința este o interfața/contract noi putem să mock-uim liniștiți interfață știind că colegul va construi adaptorul bazat pe contract.

Un și mai mare beneficiu al acestei metode este că codul nostru este acum mai scalabil. Dacă peste un an vom decide că vrem să migrăm la un alt tip de bază de date, putem scrie un adaptor care implementează interfața originală și să îl injectăm pe acela, nici un pic de refactorizare nu ar fi necesară întrucât putem fi siguri că adaptorul respectă contractul setat de interfață.

Containeri

Primul lucru pe care ar trebui sa îl înțelegi despre containerii de injectare de dependințe este că ei nu sunt același lucru ca injectarea de dependințe. Un container este o utilitate convenientă care ajută să implementăm injectarea de dependințe, dar, ei pot fi, și sunt greșit utilizați prin implementarea unui anti-șablon, Locator-ul de Servicii. Injectarea unui container ca locator de servicii în clasele noastre creează o dependență mai mare de container decât de cea pe care încerci să o înlocuiești. De asemenea iți face codul mult mai puțin transparent și mai greu de testat.

Majoritatea framework-urilor moderne au propriul container de injectare de dependințe care iți permite sa iți ții dependințele împreună prin configurație. Ce înseamnă asta în practică este că poți scrie cod de aplicație care este la fel de curat și de decuplat ca și framework-ul pe care e clădit.

Alte lecturi

Back to Top

Baze de date

De multe ori codul tău PHP va folosi o bază de date pentru a perminte informațiilor să persiste. Ai câteva opțiuni de conectare și interacțiune cu baza ta de date. Opțiunea recomandată pană la PHP 5.1.0 era sa folosești driveri nativi precum mysql, mysqli, pgsql, etc.

Driverii nativi sunt buni dacă folosești o singură bază de date în aplicația ta, dar dacă, spre exemplu, folosești MySQL și ceva MSSQL sau ai nevoie să te conectezi la o bază Oracle, atunci nu vei putea să folosești aceiași driveri. Vei avea nevoie să înveți un nou API pentru fiecare bază de date iar asta poate deveni ridicol.

Ca încă o observație asupra driverilor nativi, extensia mysql pentru PHP nu mai este dezvoltată activ, iar statusul oficial începând cu PHP 5.4.0 este “Long term deprecation”. Asta înseamnă că va dispărea în viitoarele lansări, așa că în jurul versiunii 5.6 (sau ce va veni după versiunea 5.5) extensia va fi eliminată. Dacă folosești mysql_connect() și mysql_query() în aplicația ta atunci va trebui sa o rescrii, oricum vei fi nevoit să faci acest lucru la un moment dat, cea mai bună opțiune este să înlocuiești ușor ușor mysql cu mysqli sau cu PDO ca să nu fii brusc forțat mai târziu. Dacă începi de la zero atunci în nici un caz să nu folosești extensia mysql: folosește extensia MySQLi sau PDO.

PDO

PDO este o bibliotecă de abstractizare a conexiunii cu baza de date — ce vine încorporată în PHP de la 5.1.0 — și pune la dispoziție o interfață comună de a vorbi cu diferite baze de date. PDO nu va traduce interogările tale SQL și nici nu va emula funcționalități lipsă; este doar pentru a te putea conecta la mai multe tipuri de baze de date prin același API.

Mai important, PDO te lasă să injectezi în mod sigur input extern (e.g. IDs) în interogările tale SQL fără a iți face griji despre atacuri prin injecție. Asta este posibil folosind PDO statements și parametri “bound”.

Să presupunem că un script PHP primește un ID numeric ca parametru. Acest ID ar trebui să fie folosit pentru a citi date din baza de date. Aceasta este calea greșită de a face asta:

<?php
$pdo = new PDO('sqlite:users.db');
$pdo->query("SELECT name FROM users WHERE id = " . $_GET['id']); // <-- NO!

Acest cod este foarte greșit. Inserezi un parametru brut în interogarea SQL. Asta iți va compromite securitatea într-o clipită. Imaginează-ți ca un hacker pasează un parametru id inventat apelând URL-ul astfel: http://domain.com/?id=1%3BDELETE+FROM+users. Asta va seta $_GET['id'] ca 1;DELETE FROM users care iți va șterge toți userii! Ce trebuie să faci este sa cureți inputul pentru ID folosind parametrii PDO “bound”.

<?php
$pdo = new PDO('sqlite:users.db');
$stmt = $pdo->prepare('SELECT name FROM users WHERE id = :id');
$stmt->bindParam(':id', $_GET['id'], PDO::PARAM_INT); // <-- Curatat automat de PDO
$stmt->execute();

Acesta este codul corect. Folosește un parametru bound pe o instrucțiune PDO. Asta sanitizează inputul extern pentru ID înainte ca el să fie introdus în baza de date prevenind astfel un potențial atac prin injecție.

Ar trebui de asemenea sa știi că conexiunile cu baza de date folosesc resurse și nu puține au fost cazurile în care toate resursele au fost epuizate dacă conexiunile nu au fost explicit închise. Totuși, acest lucru este mai des întâlnit în alte limbaje. Folosind PDO poți închide implicit conexiunea distrugând obiectul și asigurându-te ca toate referințele către el au fost șterse, adică setate ca NULL. Dacă nu faci asta explicit, PHP va închide automat conexiunea la sfârșitul scriptului - exceptând desigur cazul în care folosești conexiuni persistente.

Niveluri de abstractizare

Multe framework-uri dispun de propriul nivel de abstractizare care se bazează sau nu pe PDO. Acestea vor emula deseori funcționalități ale unui sistem de bază de date care lipsesc în altul îmbrăcând interogările prin metode PHP, furnizându-ți efectiv o metoda de abstractizare a bazei de date. Aceastea vor veni cu un mic preț, dar dacă construiești o aplicație portabilă care are nevoie să lucreze cu MySQL, PostgreSQL și SQLite atunci micul preț plătit va merita de dragul curățeniei codului.

Unele niveluri de abstractizare au fost construite folosind standarde namespace PSR-0 sau PSR-4 încât să poată fi instalate în orice aplicație dorești:

Back to Top

Erori și excepții

Erori

PHP are câteva niveluri de severitate a erorilor. Cele mai comune trei tipuri de mesaje sunt erorile, notificările și avertismentele. Acestea au diferite niveluri de severitate; E_ERROR, E_NOTICE, și E_WARNING. Erorile sunt probleme fatale în timpul execuției (runtime) și sunt determinate de obicei de probleme ale codului tău și trebuie reparate întrucât opresc execuția PHP. Avertismentele sunt probleme non-fatale iar execuția scriptului nu va fi oprită. Notificările sunt mesaje informative cauzate de cod care ar putea sau nu să provoace probleme în timpul execuției scriptului, execuția nu e oprită.

Alt tip de mesaje de eroare raportat la momentul compilării este mesajul E_STRICT. Aceste mesaje sunt folosite să sugereze modificări ale codului tău pentru a asigura cea mai bună interoperabilitate și compatibilitate pentru viitor.

Excepții

Excepțiile sunt o parte standard a majorității marilor limbaje de programare, dar sunt deseori trecute cu vederea de către programatorii PHP. Limbaje precum Ruby se bazează foarte mult pe excepții, așa ca oricând se întâmplă ceva greșit precum o interogare HTTP care eșuează, sau o interogare SQL, sau o imagine nu poate fi găsită, Ruby (sau gem-ul folosit) va arunca o excepție pe ecran însemnând că vei știi imediat ca există o greșeală.

PHP este destul de lax în aceasta privință, iar după o apelare la file_get_contents() te vei alege cu un FALSE și o avertizare. Multe framework-uri mai vechi precum CodeIgniter vor returna un false, vor scrie un mesaj în jurnalul propriu și poate te vor lăsa să folosești o metodă precum $this->upload->get_error() ca ce eroare a avut loc. Problema aici este ca tu trebuie să mergi să cauți greșeala și să verifici documentele să vezi care este metoda de eroare pentru acea clasa în loc ca ea să fie extrem de evidentă.

Altă problemă este când clasele aruncă o eroare automat pe ecran și opresc procesul. Când faci asta înseamnă că oprești alt programator care s-ar fi ocupat de acea eroare. Excepții ar trebui aruncate pentru a face un programator conștient de eroare; apoi el va putea să aleagă cum să se ocupe. E.g.:

<?php
$email = new Fuel\Email;
$email->subject('My Subject');
$email->body('How the heck are you?');
$email->to('guy@example.com', 'Some Guy');

try
{
    $email->send();
}
catch(Fuel\Email\ValidationFailedException $e)
{
    // Validarea a eșuat
}
catch(Fuel\Email\SendingFailedException $e)
{
    // Driver-ul nu a putut trimite email-ul
}
finally
{
    // Executat chiar și dacă o excepție a fost aruncată și înainte ca
       execuția normală să fie reîncepută
}

Excepții SPL

Clasa generică Exception pune la dispoziție foarte puțină informație pentru depanare și dezvoltator; totuși, pentru a remedia asta, este posibil să creezi o excepție specializată prin subclasarea genericei Exception:

<?php
class ValidationException extends Exception {}

Asta înseamnă că poți adăuga multiple blocuri catch și te poți ocupa de diferite Excepții în moduri diferite. Asta poate duce la crearea multor Excepții personalizate, unele din ele ar fi putut fi evitate folosind excepții SPL disponibile în extensia SPL.

Dacă de exemplu folosești metoda magică __call() și o metodă invalidă este cerută atunci în loc de aruncarea unei Excepții standard, care e vagă, sau crearea unei Excepții personalizate numai pentru asta, ai putea pur și simplu să throw new BadFunctionCallException;.

Back to Top

Securitate

Securitatea aplicațiilor web

Există oameni răi gata să îți exploateze aplicația web. Este important ca tu să iei măsurile necesare pentru a îți întări securitatea aplicației. Din fericire, amabilii băieți de la The Open Web Application Security Project (OWASP) au creat o listă largă de probleme cunoscute de securitate și metode de a te proteja împotriva lor. Asta este o lectură obligatorie pentru dezvoltatorul conștient de riscuri.

Hash-uirea parolelor

Toată lumea construiește o aplicație PHP care se bazează pană la urmă pe autentificarea utilizatorilor. Username-urile și parolele sunt stocate în baza de date iar mai târziu folosite pentru a autentifica utilizatorii.

E important ca parolele să fie bine hash-uite înainte de salvarea în baza de date. Hash-uirea parolelor este o funcție ireversibilă, mono-direcțională aplicată pe parola utilizatorului. Aceasta produce un șir de caractere de lungime fixă care nu poate fi folosit pentru a afla parola originală într-un timp fezabil. Asta înseamnă că poți compara un hash versus un altul ca să vezi dacă ambele au venit de la aceeași sir sursă, dar nu poți determina șirul original. Dacă parolele nu sunt hash-uite iar baza ta de date este accesată de un terț neautorizat, toate parolele vor fi atunci compromise. Unii utilizatori ar putea(din păcate) fii folosit aceeași parolă și la alte servicii. Așadar e important să iei în serios securitatea.

Hash-uirea parolelor cu password_hash

În PHP 5.5 a fost introdus password_hash. Momentan folosește BCrypt, cel mai puternic algoritm suportat de PHP. Va fi actualizat în curând pentru a suporta mai mulți algoritmi. Biblioteca password_compat a fost creată pentru a o face disponibilă și pentru PHP >= 5.3.7.

Mai jos hash-uim un string, și apoi verificam hash-ul împotriva unui alt string. Pentru că sursele noastre sunt diferite (‘secret-password’ vs. ‘bad-password’) autentificarea va eșua.

<?php

require 'password.php';

$passwordHash = password_hash('secret-password', PASSWORD_DEFAULT);

if (password_verify('bad-password', $passwordHash)) {
    // Correct Password
} else {
    // Wrong password
}

Filtrarea datelor

Niciodată să nu ai încredere în input străin ce intră în codul tău PHP. Totdeauna sanitizează și validează datele de intrare străine înainte de a le folosi în cod. Funcțiile filter_var și filter_input pot sanitiza text și valida formate text (e.g. adrese de email)

Input străin poate fi orice: $_GET și formulare $_POST, unele valori din super-globalul $_SERVER, și corpul interogării HTTP via fopen('php://input', 'r'). Tine minte, input-ul străin nu e limitat la date de formular trimise de utilizatori. Fișiere încărcate sau descărcate, valori de sesiune, date cookie, date de la servicii web terțe sunt de asemenea străine.

Când datele străine pot fi stocate, combinate, și accesate mai târziu, sunt încă străine. De fiecare dată când procesezi, afișezi, concatenezi sau incluzi datele în codul tău, întreabă-te dacă au fost filtrate corespunzător și dacă sunt de încredere.

Datele pot fi filtrate diferit în funcție de scopul sau. De exemplu, când input străin este pasat în conținutul paginii HTML, el poate executa HTML și Javascript pe siteul tău! Asta se numește Cross-Site Scripting (XSS) și poate fi un atac foarte periculos. O metodă de a evita un atac XSS este să sanitizezi orice data generată de utilizatori înainte de a o afișa pe pagina ta prin eliminarea tag-urilor HTML cu funcția strip_tags sau escape-ând caractere cu sens special în entitățile lor HTML respective folosind funcțiile htmlentities sau htmlspecialchars.

Alt exemplu este pasarea opțiunilor ce vor fi executate în linia de comandă. Aceasta poate fi extrem de periculos (și e de obicei o idee rea și trebuie evitată), dar poți folosi funcția încorporată escapeshellarg pentru a sanitiza argumentele comenzii executate.

Un ultim exemplu este acceptarea intrărilor străine pentru a determina ce fișier trebuie încărcat din sistemul de fișiere. Asta poate fi exploatată prin schimbarea numelui fișierului într-o cale de fișiere. Trebuie să șterge “/”, “../”, null bytes, sau alte caractere din calea fișierului așa încât să nu se poată încărca fișiere ascunse, non-publice, sau fișiere sensitive.

Sanitizare

Sanitizarea elimină (sau escape-ează) caractere ilegale sau nesigure din inputul străin.

De exemplu, ar trebui sanitizat inputul străin înainte de includerea sa în HTML sau de inserarea sa într-o interogare SQL brută. Când folosești parametri bound cu PDO, el va sanitiza input-ul pentru tine.

Uneori este necesar să lași unele tag-uri HTML permise în input atunci când îl incluzi în pagina HTML. Acest lucru este foarte greu de făcut iar mulți evita asta prin folosirea unui mod de formatare mai restricționat precum Markdown sau BBCode, deși biblioteci de validare precum HTML Purifier există exact pentru acest scop.

Vezi filtre de sanitizare

Validare

Validarea are menirea de a oferi garanția că inputul străin este ceea ce te așteptai sa fie. De exemplu, ai putea dori să validezi o adresa email, un număr de telefon, sau vârsta când procesezi o cerere de înregistrare.

Vezi filtre de validare

Fișiere de configurare

Când creezi fișiere de configurare, bunele practici recomandă ca una dintre următoarele metode să fie folosită:

Register Globals

NOTA: Începând cu PHP 5.4.0 setarea register_globals a fost eliminată și nu mai poate fi folosită. Prezenta este inclusă numai ca o avertizare pentru cei ce se află în proces de actualizare a unei aplicații vechi.

Când este activată, setarea de configurare register_globals face ca unele tipuri de variabile (inclusiv $_POST, $_GET și $_REQUEST) să fie disponibile în scope-ul global al aplicației. Asta poate duce foarte ușor la probleme de securitate pentru că aplicația ta nu poate stabili de unde provin datele.

De exemplu: $_GET['foo'] ar deveni disponibilă via $foo, care poate suprascrie variabile care nu au fost declarate. Dacă folosești PHP < 5.4.0 fii sigur ca register_globals este off.

Raportarea erorilor

Log-area (jurnalizarea) erorilor poate fi utilă pentru a afla de existența eventualelor probleme în aplicația ta, dar, de asemenea, poate expune informații despre structura aplicației tale lumii externe. Pentru a-ți proteja aplicația de probleme ce ar putea fi cauzate de afișarea acestor mesaje, trebuie să iți configurezi serverul diferit pentru dezvoltare decât pentru producție (live).

Dezvoltare

Pentru a arăta toate erorile posibile în timpul dezvoltării, asigurați-vă că ați configurat într-un mod corespunzător următoarele setări din php.ini:

display_errors = On
display_startup_errors = On
error_reporting = -1
log_errors = On

Pasarea valorii -1 va arăta toate erorile posibile, chiar și când noi niveluri și constante sunt adăugate în viitoare versiuni PHP. Constanta E_ALL se comportă în acest fel începând cu PHP 5.4.- php.net

Nivelul de erori E_STRICT a fost introdus în 5.3.0 și nu făcea parte din E_ALL, dar totuși a devenit parte din E_ALL în 5.4.0. Ce înseamnă asta? În termeni de raportarea fiecărei posibile erori în 5.3 înseamnă ca trebuie să folosești ori -1 ori E_ALL | E_STRICT.

Raportare tuturor erorile posibile în funcție de versiunea PHP

Producție

Pentru a ascunde erorile pe mediul vostru de producție, configurați-vă php.ini precum:

display_errors = Off
display_startup_errors = Off
error_reporting = E_ALL
log_errors = On

Cu aceste setări în producție, erorile vor fi înregistrate în log-urile de erori de pe serverul web, dar nu vor fi afișate utilizatorului. Pentru mai multe informații despre aceste setări, consultați manualul PHP:

Back to Top

Testare

Scrierea testelor automate pentru codul tău PHP este considerată o bună practică și poate duce la aplicații bine construite. Testele automate sunt o unealtă grozavă pentru a fii sigur ca aplicația ta nu se strică atunci când faci modificări sau adaugi noi funcționalități și deci nu ar trebui ignorate.

Există câteva tipuri diferite de unelte de testare (sau framework-uri) disponibile în PHP, care folosesc diferite abordări - toate încercând să evite testarea manuală sau nevoia de mari echipe de controlul calității, doar pentru a fii siguri că modificări recente nu strică funcționalitatea deja existentă.

Dezvoltarea centrata pe teste

De la Wikipedia:

Dezvoltarea centrata pe teste (TDD) este un proces de dezvoltare software care se bazează pe repetiția unui foarte scurt ciclu de dezvoltare: mai întâi programatorul scrie un test care eșuează care descrie o îmbunătățire sau o nouă funcționalitate, apoi produce codul care va satisface acel test iar în final rescrie codul cel nou într-o maniera compatibila cu standarde. Kent Beck, care este creditat cu dezvoltarea sau ‘redescoperirea’ acestei tehnici, spunea în 2003 ca TDD încurajează arhitecturi simple și inspira încredere

Exista câteva tipuri diferite de testare pe care le poți implementa în aplicațiile tale.

Testarea unitara

Testarea unitara este o abordare programatica pentru a asigura ca funcțiile, clasele și metodele funcționează precum ne așteptăm, de la momentul construcției lor și prin tot parcursul ciclului de dezvoltare. Verificând valorile de intrare și ieșire din diferite funcții și metode, te poți asigura ca logica interna funcționează corect. Pentru o testare de și mai mare amploare, folosind injectarea de dependințe și construind clase “mock” și cioturi poți verifica ca dependințele sunt folosite corect.

Când creezi o clasa sau o funcție ar trebui sa creezi și un test unitar pentru fiecare comportament pe care trebuie sa îl aibă. Ca un minimum ar trebui sa te asiguri ca este produsa o eroare dacă ii sunt furnizate argumente incorecte și ca funcționează când sunt primite argumente valide. Asta va asigura ca atunci când mai târziu în ciclul de dezvoltare faci schimbări în aceasta clasa sau funcție, vechea funcționalitate va continua sa meargă precum ne așteptăm. Singura alternativa la ar fi var_dump() într-un test.php, ceea ce desigur nu e o opțiune serioasa.

Celalalt uz al testelor unitare este contribuirea la open source. Dacă poți scrie un test care demonstrează funcționalitate stricata (adică eșuează), și îl și repari, și arăți apoi ca testul trece cu bine, apoi patch-urile vor avea mult mai multe șanse sa fie acceptate. Dacă conduci un proiect care accepta cereri pull atunci ar trebui sugerezi asta ca o cerință.

PHPUnit este framework-ul de-facto pentru scrierea de teste unitare pentru aplicațiile PHP, dar exista și alternative

Testarea integrării

De la Wikipedia:

Testarea integrării (uneori numită Integrare și Testare, abreviat “I&T”) este faza în testarea software-ului în care module individuale sunt combinate și testate ca un grup. Se întâmplă după testarea unitară și înainte de testarea validării. Testarea integrării ia ca input modulele care au fost testate unitar, le grupează în agregate mai mari, aplică testele definite în planul de test asupra acelor agregate, și livrează ca output sistemul integrat gata pentru testarea sistemului.

Multe dintre aceleași unelte care pot fi folosite pentru testare unitară pot fi folosite și pentru testarea integrării pentru ca multe dintre aceleași principii sunt folosite.

Testare funcțională

Uneori cunoscută și drept testare a acceptării, testarea funcțională înseamnă folosirea de unelte pentru a crea automat teste care folosesc cu adevărat aplicația în loc de a verifica doar că bucăți de cod individuale se comportă corect sau că pot vorbi între ele. Aceste unelte operează de obicei folosind date reale și simulează utilizatorii reali ai aplicației.

Unelte de testare funcțională

Dezvoltare centrata pe comportament

Exista doua tipuri diferite de dezvoltare centrata pe comportament (BDD): SpecBDD și StoryBDD. SpecBDD se concentrează pe comportamentul tehnic al codului, în timp ce StoryBDD se concentrează pe business sau comportamentul funcționalităților sau pe comportamentul interacțiunilor. Exista framework-uri PHP pentru ambele tipuri de BDD.

Cu StoryBDD, tu scrii povestioare citibile de om, care descriu comportamentul aplicației tale. Aceste povestioare pot fi apoi rulate ca teste efective asupra aplicației tale. Framework-ul folosit în aplicații PHP pentru StoryBDD este Behat, care este inspirat de proiectul Cucumber din Ruby, și care implementează Gherkin DSL pentru descrierea comportamentului funcționalităților.

Cu SpecBDD, poți scrie specificații care descriu cum propriul cod trebuie să se comporte. În loc de a testa o funcție sau o metodă, tu descrii cum acea funcție sau metodă ar trebui să se comporte. PHP oferă framework-ul PHPSpec pentru aceasta. Acest framework este inspirat de proiectul RSpec pentru Ruby.

Unelte de testare complementare

În afara de testarea individuală și de framework-urile pentru testarea comportamentului, există de asemenea și un număr de framework-uri generice și biblioteci ajutătoare utile pentru oricare abordare preferată.

Link-uri spre unelte

Back to Top

Servere și Lansare

Aplicațiile PHP pot fi lansate (deployed) și rulate pe servere de producție într-un număr de moduri.

Platforma ca un Serviciu (PaaS)

PaaS ne pune la dispoziție sistemul și arhitectura necesară pentru a rula aplicații PHP pe web. Asta înseamnă configurare puțină sau deloc pentru lansarea aplicațiilor PHP sau framework-urilor PHP.

Recent PaaS a devenit o metodă populară pentru lansarea, găzduirea, și scalarea aplicațiilor PHP de toate mărimile. Poți găsi o listă de furnizori de PHP ca platforma ca serviciu în secțiunea de resurse.

Servere virtuale sau dedicate

Dacă ești confortabil cu administrarea sistemului, sau ești interesat în învățarea lui, serverele virtuale sau dedicate iți dau control complet asupra mediului de producție al aplicației tale.

nginx și PHP-FPM

PHP, prin al său FastCGI Process Manager (FPM), se îmbină armonios cu nginx, care este un web server suplu și de înaltă performanță. Folosește mai puțină memorie ca Apache și poate susține mai multe interogări concomitente. Asta este în mod special important pe servere virtuale care nu au prea multă memorie de irosit.

Apache and PHP

PHP și Apache au o lungă istorie împreună. Apache este foarte configurabil și are multe module disponibile care îi extind funcționalitatea. Este o alegere populară pentru serverele comune și o configurație ușoară pentru framework-urile PHP sau aplicațiile open source gen Wordpress. Din păcate, Apache folosește mai multe resurse decât nginx în instalarea obișnuită și nu poate manipula tot atât de mulți vizitatori în același timp.

Apache are câteva posibile configurări pentru rularea PHP. Cea mai comună și ușoară de configurat este prefork MPM cu mod_php5. Deși nu este cea mai eficientă, este cea mai simplă de folosit. Asta este probabil cea mai bună alegere dacă nu vrei sa te afunzi prea mult în administrarea serverului. Nota: dacă folosești mod_php5 trebuie sa folosești prefork MPM.

Alternativ, dacă vrei sa storci mai multa performanță și stabilitate din Apache atunci poți profita de același system FPM ca și nginx și vei rula worker MPM sau eventMPM cu mod_fastcgi sau mod_fcgid. Configurarea aceasta va fi semnificativ mai eficientă și mai rapidă dar este mai complicat de setat.

Servere comune

PHP are serverelor comune (partajate) să le mulțumească pentru popularitatea sa. E greu sa găsești o gazdă fără PHP instalat, dar încearcă să te asiguri că este ultima versiune. Serverele comune iți permit ție și altor programatori să lansezi siteuri pe o singură mașină. Partea bună este că a devenit un bun de larg consum. Partea proastă este că nu știi niciodată ce fel de scandal vor crea vecinii tăi; încărcând astfel serverul sau deschizând găuri de securitate. Dacă bugetul proiectului tău iți permite să eviți servere comune atunci e bine să o faci.

 

Asamblarea și lansarea aplicației tale

  Dacă te surprinzi modificând schema bazei de date manual sau rulând testele manual înaintea actualizării fișierelor tale(manual), mai gândește-te! Cu fiecare task manual adițional necesar pentru lansarea unei noi versiuni a aplicației tale, șansa unor greșeli fatale crește dacă ai de-a face cu un simplu update, un proces de construcție complicat sau chiar o strategie de integrare continuă, automatizarea asamblării este prietena ta.   Printre pașii pe care ai putea dori sa îi automatizezi s-ar putea numără:  

Unelte de automatizare a asamblării

Unelte pentru asamblarea aplicației pot fi descrise ca o colecție de scripturi care execută instrucțiuni des întâlnite în dezvoltarea de software. Unealta de asamblare nu este parte a software-ului tău, ea acționează asupra soft-ului tău din ‘afară’.

Există multe unelte open source disponibile care te pot ajuta cu automatizarea asamblarii, unele sunt scrise în PHP iar altele nu. Asta nu ar trebui să te descurajeze din a le folosi, dacă sunt mai bine potrivite pentru jobul respectiv. Aici sunt câteva exemple:

Phing este cea mai ușoară cale de a începe lansare automată în lumea PHP. Cu Phing tu îți controla împachetarea, transportul sau procesul de testare dintr-un simplu fișier XML. Phing (care e bazat pe Apache Ant) pune la dispoziție un bogat set de instrucțiuni de obicei necesare pentru actualizarea sau instalarea unei aplicații web și poate fi extins cu instrucțiuni personalizate adiționale, scrise în PHP.   Capistrano este un sistem pentru programatori intermediari-spre-avansați pentru a executa comenzi, într-o manieră structurată și repetabilă pe una sau mai multe mașini externe. Este pre-configurat pentru lansarea de aplicații Ruby on Rails, dar totuși se pot lansa cu succes și sisteme PHP cu el. Uzul cu succes al Capistrano depinde de cunoștințe în Ruby și Rake.   Blogpost-ul lui Dave Gardner Lansare PHP cuCapistrano este un bun punct de plecare pentru dezvoltatorii PHP interesați de Capistrano.   Chef este mai mult decât un framework de lansare a codului, este un puternic system de integrare bazat pe Ruby care nu numai iți transporta aplicația dar iți poate construi întregul server sau mașini virtuale.   Resurse Chef pentru programatori PHP:  

Integrare continuă

 

Integrarea continua este o practică a dezvoltării software unde membrii unei echipe isi integrează munca frecvent, de obicei fiecare persoana integrează cel puțin zilnic — ducând la mai multe integrări pe zi. Multe echipe găsesc ca aceasta abordare duce la un număr semnificativ mai mic de probleme de integrare și permite unei echipe să dezvolte software consistent mai rapid.

  – Martin Fowler   Există diferite metode de a implementa integrare continuă pentru PHP. Recent Travis CI a făcut ca integrarea continua sa devină o realitate chiar și pentru proiecte mici. Travis CI este un serviciu găzduit de integrare continuă pentru comunitatea open source. Este integrat cu GitHub și oferă suport de prima mână pentru multe limbaje inclusiv PHP.   Lecturi aprofundate:  

Back to Top

Caching

PHP este destul de rapid luat de unul singur, dar pot exista latențe când faci conexiuni externe, încarci fișiere, etc. Din fericire, există diverse unelte disponibile care iți pot accelera unele părți ale aplicației, sau pot reduce numărul de câte ori aceste instrucțiuni consumatoare de timp trebuie să fie rulate.

Cache de bytecode

Când un fișier PHP este executat, sub capota este mai întâi compilat în bytecode (cunoscut și ca opcode) și, numai apoi, bytecode-ul este executat. Dacă fișierul PHP nu este modificat, bytecode-ul va fi întotdeauna același. Asta înseamnă că pasul de compilare este o risipa ale resurselor procesorului.

Aici intra în scena Cache-ul de bytecode. El previne compilarea redundantă stocând bytecode-urile în memorie și refolosindu-le la apelări ulterioare. Setarea cache-ului de bytecode este o chestiune de minute, și aplicația ta va fi semnificativ mai rapidă. Nu prea există motive de a nu îl folosi.

Începând cu PHP 5.5, există un cache de bytecode încorporat numit OPCache. Este disponibil și pentru versiuni mai vechi.

Alte cache-uri de bytecode populare sunt:

Cache-uirea obiectelor

Exista momente când poate fi benefic să cache-uiesti obiecte individuale în codul tău, de exemplu cu date care sunt scump de obținut sau cu apeluri către baza de date care sunt improbabil de a se fi schimbat. Poți folosi software pentru cache-iuirea obiectelor pentru a ține aceste bucăți de date în memorie pentru acces rapid mai târziu. Dacă salvezi aceste date într-o datastore după ce le recuperezi, atunci iai direct din cache data viitoare când ai nevoie de ele, poți câștiga o îmbunătățire semnificativa a performantei ca și o reducere a încărcării serverului bazei de date.

De asemenea, multe din soluțiile populare de cache-uire a bytecode-ului te lasă să stochezi și date personalizate, asa că ai chiar și mai multe motive să profiți de ele. APCu, XCache, si WinCache toate pun la dispoziție API-uri pentru a salva date din codul tău PHP în memoria lor.

Cele mai populare sisteme de cache-uire a obiectelor sunt APCu și memcached. APCu este o excelentă alegere pentru cache-ul de obiecte, are un API simplu pentru inserarea datelor tale în memoria sa cache si este foarte simplu de folosit. Singura limitare a APCu este că este legată de serverul pe care e instalată. Memcached pe de altă parte este instalat ca un serviciu separat și poate fi accesat prin intermediul rețelei, însemnând ca poți stoca obiecte într-o magazie super-rapidă, într-o locație centrală, și mai multe sisteme diferite pot citi din ea.

Nota: când rulam PHP ca aplicație (Fast-)CGI inauntrul webserver-ului, fiecare proces PHP va avea propriul cache, adică datele APCu nu sunt la comun pentru toate procesele. În aceste cazuri, probabil ai vrea să folosești memcached, întrucât nu e legat de procesele PHP.

Într-o configurație cu rețea, APCu va performa mai bine decât memcached în termeni de viteză, dar memcached va putea să scaleze mai rapid și mai departe. Dacă nu te aștepți să ai mai multe servere pentru aplicația ta, sau nu ai nevoie de funcționalitate extra oferite de memcached atunci APCu este probabil cea mai bună alegere pentru stocarea obiectelor.

Exemplu de logica folosind APCu:

<?php
// afla dacă există date salvate ca 'expensive_data' în cache
$data = apc_fetch('expensive_data');
if ($data === false) {
    // data nu e în cache; salvăm rezultatul dupa apelare scumpă pentru uz ulterior
    apc_add('expensive_data', $data = get_expensive_data());
}

print_r($data);

De notat ca înainte de PHP 5.5, APC pune la dispoziție atât un cache de obiecte cât și un cache de bytecode. APCu este un proiect care aduce cache-ul de obiecte al lui APC în PHP 5.5+, întrucât PHP are de acum deja un bytecode cache încorporat (OPCache).

Află mai multe despre sisteme populare de cache al obiectelor:

Back to Top

Resurse

De la sursă

Oameni de urmărit

Mentoring

Furnizori de PHP PaaS

Framework-uri

Decât sa reinventeze roata, multi dezvoltatori PHP folosesc framework-uri ca să construiască aplicații web. Framework-urile abstractionează multe dintre problemele de baza și pun la dispoziție interfețe ușor de folosit pentru a realiza acțiuni des întâlnite.

Nu ai nevoie să folosești un framework pentru toate proiectele. Uneori PHP simplu este calea cea mai bună, dar dacă totuși ai nevoie de un framework atunci există cam trei tipuri principale disponibile:

Micro-framework-uri sunt în esență o împachetare pentru a ruta interogarea HTTP către o funcție callback, un controller, o metodă, etc cât mai rapid posibil, dar uneori vin cu câteva biblioteci extra pentru a asista dezvoltarea precum wrappere simple pentru baza de date etc. Sunt folosite mai ales pentru a construi servicii HTTP externe.

Multe framework-uri adaugă un număr considerabil de funcționalități deasupra a ce este disponibil într-un micro-framework iar acestea sunt numite framework-uri de tip Full-Stack (de “întreaga stiva”). Acestea de obicei vin la pachet și cu ORM-uri, pachete de autentificare etc.

Framework-urile bazate pe componente sunt colecții de biblioteci specializate. Disparate framework-uri de componente pot fi folosite împreună pentru a face un framework micro- sau un full-stack.

Componente

După cum am menționat mai sus, “Componente” sunt altă abordare în a crea, distribui și implementa cod comun. Diverse repository-uri există dar principalele sunt:

Ambele au unelte de linie de comandă asociate pentru a ajuta instalarea și procesul de actualizare, și au fost explicate mai în detaliu din secțiunea Dependency Management.

Există de asemenea și framework-uri bazate pe componente care te lasă să le folosești componentele cu cerințe minime (sau deloc). De exemplu poți folosi pachetul de validare FuelPHP, fără să ai nevoie sa folosești framework-ul Fuel în sine. Aceste proiecte sunt în esență doar încă un repository pentru componente reutilizabile:

Back to Top

Comunitate

Comunitatea PHP este pe cât de mare pe atât de diversă, iar membrii săi sunt gata să ajute noii programatori PHP. Gândește-te să te alături grupului local de utilizatori PHP (PUG) sau să participi la conferințele mai mari PHP pentru a învăța mai multe despre cele mai bune practici. Poți sta pe IRC pe canalul #phpc de pe irc.freenode.com sau poți urmări contul de twitter @phpc. Implică-te, fă cunoștință cu noi dezvoltatori, află despre topicuri noi, și, mai presus de toate, fă-ți prieteni! Alte resurse ale comunității includ comunitatea de programatori PHP de pe Google+ și StackOverflow.

Citește calendarul oficial de evenimente PHP

Grupurile de utilizatori PHP

Dacă trăiești într-un oraș mai mare, ai șansa de a exista un grup de utilizatori prin jur. Deși nu există o listă oficială de PUG-uri, poți găsi cu ușurință grupul local căutând pe Google, Meetup.com sau PHP.ug. Dacă trăiești într-un oraș mai mic, s-ar putea să nu existe un grup local; dacă acesta este cazul pornește tu unul!

Citește despre grupurile de utilizatori pe wiki-ul PHP

Conferințe PHP

Comunitatea PHP găzduiește de asemenea și conferințe regionale sau naționale în multe tari din jurul lumii. Membrii bine cunoscuți ai comunității PHP vorbesc de obicei la aceste evenimente mai mari, așa că este o oportunitate perfectă de a învață direct de la liderii industriei.

Găsește o conferință PHP

Back to Top