Pozdravljeni

Na spletu je ogromno zastarelih informacij, ki vodijo nove uporabnike PHP v napačno smer, propagirajo slabe prakse in nezaščiteno kodo. PHP: The Right Way je hitro priporočilo enostavno za branje popularnih kodnih standardov PHP, povezav k avtoriziranim vodnikom po spletu in, kar pojmujejo uporabniki, ki prispevajo kodo, najboljša praksa ta trenutek.

Trenutno ni dogovorjene poti za uporabo PHP-ja. Ta stran teži k predstavitvi nekaterih tem novim razvijalcem PHP, ki jih ne odkrijejo, dokler ni že prepozno, ter nudi izkušenim profesionalcem nove ideje na teh temah, ki so jih uporabljali že leta, brez da bi o njih ponovno premislili. Ta stran vam tudi ne bo narekovala, katera orodja naj uporabljate, vendar namesto tega ponuja predloge za mnoge možnosti, ko je možno razložiti razlike v pristopu in primerih uporabe.

Gre za dokument, ki se vedno razvija in bo vedno posodabljan z več uporabnimi informacijami in primeri, ko bodo na voljo.

Prevodi

PHP: The Right Way je preveden v mnoge različne jezike:

Knjiga

Najnovejša verzija PHP: The Right Way je navoljo tudi v formatih PDF, EPUB in MOBI. Obiščite Leanpub

Kako prispevati

Pomagajte tej strani narediti najboljši vir za nove programerje PHP! Prispevajte preko GitHuba

Nazaj na vrh

Pričetek

Uporabite trenutno stabilno različico (8.2)

Če pričenjate s PHP-jem, uporabite trenutno stabilno različico izdaje PHP 8.2. PHP 8.x vsebuje mnoge nove lastnosti napram starejšim različicam 7.x in 5.x. Motor je bil v večini na novo napisan in PHP je sedaj celo hitrejši od starejših različic. PHP 8 je glavna nadgradnja jezika in vsebuje mnoge nove lastnosti in optimizacije.

Čim hitreje bi morali poskusiti nadgraditi na zadnjo stabilno različico - PHP 7.4 je že dosegel konec življenskega cikla. Nadgradnja je enostavna, saj ni veliko nazaj nezdružljivih sprememb PHP 8.0, PHP 8.1, PHP 8.2. Če niste prepričani, v kateri različici je določena funkcija ali lastnost, lahko preverite dokumentacijo PHP na strani php.net.

Vgrajeni spletni strežnik

S PHP 5.4 ali novejšim se lahko začnete učiti PHP brez namestitve ali konfiguracije celotnega spletnega strežnika. Za zagon strežnika poženite naslednje iz ukazne vrstice v vašem vrhnjem spletnem direktoriju:

> php -S localhost:8000

Namestitev v okolju macOS

macOS sicer že vsebuje PHP, vendar ponavadi ne vsebuje zadnje stabilne verzije. Obstaja več načinov za namestitev zadnje verzije jezika PHP na macOS.

Namestitev PHP preko Homebrew

Homebrew je paketni urejevalnik za macOS, ki omogoča enostavno namestitev jezika PHP ter različnih razširitev. Homebrew glavni repozitorij ponuja »formule« za PHP 7.4, 8.0, 8.1 in PHP 8.2. Zadnjo različico lahko namestite s sledečim ukazom:

brew install php@8.2

Če želite preklapljati med različnimi verzijami PHP-ja, lahko to storite s spreminjanjem vaše spremenljivke PATH. Druga možnost je uporaba brew-php-switcher, ki bo različico preklopil avtomatsko za vas.

Med različicami PHP lahko preklapljate tudi ročno z dodajanjem ali odstranjevanjem povezav na željene različice:

brew unlink php
brew link --overwrite php@8.1
brew unlink php
brew link --overwrite php@8.2

Namestitev PHP preko Macports

Projekt MacPorts je pobuda odprtokodne skupnosti načrtovati sistem enostaven za uporabo, za prevajanje, nameščanje in nadgradnjo bodisi ukazne vrstice, X11 ali Aqua osnovane odprtokodne programske opreme na operacijskem sistemu macOS.

MacPorts podpira vnaprej prevedene zagonske datoteke, tako da vam ni potrebno prevajati vsake odvisnosti iz izvornih datotek stisnjenih arhivov tar, olajša vam življenje, tudi če nimate nameščenega nobenega paketa na vašem sistemu.

Trenutno lahko namestite php54, php55, php56, php71, php72, php73, php74, php80, php81, ali php82 z uporabo ukaza port install. Na primer:

sudo port install php81
sudo port install php82

Poženete lahko ukaz select, da preklopite vaš aktivni PHP:

sudo port select --set php php82

Namestitev PHP preko phpbrew

phpbrew je orodje za namestitev in upravljanje različnih različic PHP. To je lahko res uporabno, če dve različni aplikaciji ali projekta zahtevata različni verziji PHP in ne uporabljate virtualnih naprav.

Namestitev PHP preko zagonskega namestitvenega programa Liip

Druga popularna opcija je php-osx.liip.ch, ki ponuja eno vrstične namestitvene metode za različice 5.3 do 7.3. Ne prepisuje PHP zagonskih datotek nameščenih s strani Apple, vendar namesti vse na ločeno lokacijo (/usr/local/php5).

Prevajanje iz izvorne kode

Druga opcija. ki vam da nadzor nad različico PHP-ja, ki ga nameščate, je da ga prevedete sami. V tem primeru se prepričajte, da imate nameščen Xcode, ali pa Applov nadomestek “Command Line Tools for XCode”, ki ga je mogoče prenesti iz Apple Developer Center.

Namestitveni programi vse-v-enem

Rešitve napisane zgoraj v glavnem upravljajo sam PHP in ne podpirajo stvari, kot so Apache, Nginx ali SQL server. Rešitve »vse-v-enem«, kot sta MAMP in XAMPP, vam bodo namestile ostale dele programske opreme in jih skupaj povezale, vendar enostavnost namestitve pride s pomanjkanjem fleksibilnosti.

Namestitev v okolju Windows

Zagonske datoteke lahko prenesete iz windows.php.net/downloads. Po razširitvi datotek PHP-ja je priporočljivo nastaviti PATH na vrhovni direktorij vašega direktorija PHP (kjer se nahaja php.exe), da lahko izvršite PHP iz kjerkoli.

Za učenje in lokalni razvoj lahko uporabite vgrajeni spletni strežnik s PHP 5.4+, tako da vam ni treba skrbeti za njegovo konfiguracijo. Če želite »vse v enem«, ki vključuje celoten spletni strežnik in tudi MySQL, potem orodja, kot so XAMPP, EasyPHP, OpenServer in WAMP, pripomorejo k hitri namestitvi na razvojno okolje Windows. Tako bodo orodja malenkost drugačna od produkcijskih, zato bodite previdni na razlike v razvojnih okoljih, če delate na Windowsu in nalagate na Linux.

Če potrebujete zagnati vaš produkcijski sistem na Windows, potem vam bo IIS7 zagotovil najbolj stabilno in najboljše izvajanje. Lahko uporabite phpmanager (GUI vtičnik za IIS7), ki enostavno skonfigurira in upravlja PHP. IIS7 vsebuje že vgrajen FastCGI in je pripravljen na uporabo, tako da potrebujete samo skonfigurirati PHP kot krmilnik. Za podporo in dodatne vire je na voljo namensko področje na iis.net za PHP.

V splošnem lahko poganjanje vaše aplikacije v različnih okoljih v razvoju in produkciji vodi do čudnih hroščev, ko naložite v živo. Če razvijate na Windowsu in nalagate na Linux (ali na karkoli, ki ni Windows), potem bi morali razmisliti o uporabi virtualne naprave.

Chris Tankersley ima zelo uporabno objavo blog, katera orodja uporablja za razvoj PHP z uporabo Windowsa.

Skupna struktura direktorijev

Pogosto vprašanje med tistimi, ki začenjajo s pisanjem programov za splet je, »Kam dam svoje stvari?«. Tekom let je bil pogost odgovor na to »Tja, kjer je DocumentRoot«. Čeprav ta odgovor ni celovit, je odličen začetek.

Zaradi razlogov varnosti, nastavitvene datoteke ne smejo biti dostopne s strani javnosti; torej, javne skripte se nahajajo v javnem direktoriju in zasebne nastavitve in podatki so shranjeni izven tega direktorija.

Za vsako ekipo, CMS, ali ogrodje, s katerim nekdo dela, je na voljjo standardna struktura direktorijev za vsako od le-teh. Vendar, če nekdo začenja s projektom samostojno, zna biti zastrašujoče vedeti, katero strukturo uporabiti.

Paul M. Jones je opravil odlično raziskavo glede skupnih praks za deset tisoče projektov GitHub na področju PHP. Izdelal je standardno strukturo datotek in direktorijev, t. i. Standard PHP Package Skeleton, osnovan na tej raziskavi. V tej strukturi direktorijev mora DocumentRoot kazati na public/, testi enot morajo biti v direktoriju tests/ in knjižnice tretjih oseb, kakršne so tiste nameščene s pomočjo upravljalnika Composer, spadajo v direktorij vendor/. Za ostale datoteke in direktorije bo spoštovanje Standard PHP Package Skeleton najbolj smiselno za ljudi, ki prispevajo projektu.

Nazaj na vrh

Vodnik za slog kode

Skupnost PHP je velika in raznolika ter sestavljena iz številnih knjižnic, ogrodij in komponent. Za razvijalce PHP je običajno, da izberejo nekaj le teh in jih združijo v skupni projekt. Pomembno je, da se koda PHP oprijema (kolikor je le mogoče) skupnega sloga kode, da je razvijalcem mešanje in kombiniranje različnih knjižnic za njihove projekte enostavnejše.

Skupina Framework Interop je predlagala in odobrila serijo priporočil o slogu. Vsa niso vezana na slog kode, vendar tista ki so, so PSR-1, PSR-12, PSR-4 in PER Coding Style. Ta priporočila so le skupek pravil, ki jih uporabljajo številni projekti, kot so Drupal, Zend, Symfony, Laravel, CakePHP, phpBB, AWS SDK, FuelPHP, Lithium itd. Lahko jih uporabite v svojih projektih, ali pa nadaljujete z uporabo vašega osebnega sloga.

Idealno bi morali pisati kodo PHP, ki se drži poznanih standardov. To je lahko kakršnakoli kombinacija PSR-jev, ali enega izmed kodnih standardov izdelanih s strani PEAR ali Zend. To pomeni, da lahko ostali razvijalci enostavno berejo in delajo z vašo kodo. Aplikacije, ki implementirajo komponente, imajo lahko enotnost tudi, ko se uporablja veliko kode tretjih oseb.

Lahko uporabite PHP_CodeSniffer, da preverite kodo glede na kateregakoli od teh priporočil in vtičnike za urejevalnike besedil, kot je Sublime Text, ki nudi povratno informacijo v realnem času.

Postavitev kode lahko popravite avtomatično z uporabo enega izmed naslednjih orodij:

PHP_CodeSniffer lahko poženete ročno v terminalu:

phpcs -sw --standard=PSR1 file.php

Prikazal bo napake in opisal, kako jih popraviti. Lahko je tudi v pomoč pri vključevanju tega ukaza v kljuko Git. Na ta način ni mogoče vnesti v repozitorij vej, ki vsebujejo kršitve izbranega standarda, dokler se teh kršitev ne odpravi.

Če imate PHP_CodeSniffer, lahko sporočene težave postavitve kode avtomatsko popravite s PHP Code Beautifier and Fixer.

phpcbf -w --standard=PSR1 file.php

Druga možnost je uporaba orodja PHP Coding Standards Fixer. Prikazalo bo, kakšne vrste napak je imela struktura kode pred popravki.

php-cs-fixer fix -v --rules=@PSR1 file.php

Angleščina je priporočljiva za vsa imena simbolov in infrastruktur kode. Komentarje lahko pišete v kateremkoli jeziku, ki ga lahko enostavno preberejo vse trenutne in bodoče stranke, ki bodo delale s kodo.

Za konec pa še dober dodatni vir za pisanje čiste kode - Clean Code PHP.

Nazaj na vrh

Povzetek jezika

Programske paradigme

PHP je fleksibilen, dinamičen jezik, ki podpira celo vrsto programskih tehnik. Tekom let se je izjemno razvijal, še posebej z dodatkom objektno orientiranega modela v PHP 5.0 (2004), anonimnih funkcij in imenskih prostorov (namespaces) v PHP 5.3 (2009) ter t. i. traits v PHP 5.4 (2012).

Objektno orientirano programiranje

PHP ima celoten nabor lastnosti objektnega programiranja, katere vključujejo podporo za razrede (classes), abstraktne razrede, vmesnike (interfaces), dedovanje, konstruktorje, kloniranje, izjeme in še več.

Funkcijsko programiranje

PHP podpira prvo razredne funkcije, kar pomeni, da je lahko funkcija dodeljena spremenljivki. Tako uporabniško definirane ali vgrajene funkcije se lahko sklicujejo na spremenljivko in se jih kliče dinamično. Funkcije se lahko podaja kot argumente drugim funkcijam (lastnost višjega reda - funkcije higher-order) in funkcije lahko vrnejo tudi druge funkcije.

Rekurzija, lastnost, ki dovoljuje funkciji, da kliče samo sebe, je podprta v jeziku, vendar večina kode PHP se osredotoča na iteracije.

Nove anonimne funkcije (s podporo za zaprtja - closures) so prisotne od PHP 5.3 (2009).

PHP 5.4 je dodal zmožnost za vezavo zapiranj (angl. bind closures) obsega objekta in tudi izboljšano podporo klicajočih, tako da so lahko uporabljene neodvisno z anonimnimi funkcijami v skoraj vseh primerih.

Meta programiranje

PHP podpira vrsto oblik meta programiranja skozi mehanizme, kot so Reflection API in magične metode. Na voljo je veliko magičnih metod, kot so __get(), __set(), __clone(), __toString(), __invoke() itd. Te omogočajo razvijalcem, da se povežejo v obnašanje razreda. Ruby razvijalci pogosto pravijo, da v PHP-ju manjka method_missing, vendar je na voljo kot __call() in __callStatic().

Imenski prostori (angl. namespaces)

Kot je omenjeno zgoraj, ima skupnost PHP veliko razvijalcev, ki ustvarijo ogromno kode. To pomeni, da določena koda knjižnice PHP lahko uporabi enako ime drugega razreda. Ko sta obe knjižnici uporabljeni v istem imenskem prostoru, lahko sovpadata in povzročata težave.

Imenski prostori rešujejo ta problem. Kot je opisano v referenčnem priročniku PHP, lahko primerjamo imenske prostore z direktoriji operacijskega sistema, ki poimenujejo prostor datotek; dve datoteki z enakim imenom lahko obstajata v različnih direktorijih. Enako lahko tudi dva razreda PHP z enakim imenom obstajata v različnih imenskih prostorih PHP. Tako enostavno je.

Pomembno je, da vašo kodo prostorsko poimenujete, da je lahko uporabljena s strani drugih razvijalcev brez strahu pred sovpadanjem z drugimi knjižnicami.

Ena izmed priporočenih poti za uporabo imenskih prostorov je poudarjena v PSR-4, ki cilja ponujati standardizirano konvencijo za datoteke, razrede in imenske prostore, da omogoča kodo plug-in-play.

V oktobru 2014 je PHP-FIG opustil prejšnji standard za avtomatsko nalaganje: PSR-0. Tako PSR-0 kot PSR-4 sta še vedno popolnoma uporabna. Slednji zahteva PHP 5.3, tako da mnogi PHP 5.2 projekti vsebujejo PSR-0.

Če nameravate uporabiti standard za avtomatsko nalaganje za novo aplikacijo ali paket, preverite PSR-4.

Standardna knjižnica PHP

Standardna knjižnica PHP (SPL - Standard PHP Library) je zapakirana v PHP in ponuja zbirko razredov in vmesnikov. Izdelana je primarno iz pogoste uporabe potrebnih podatkovno strukturiranih razredov (stack, queue, heap, itd.) in iteratorjev, ki lahko prečkajo te podatkovne strukture, ali pa vaši lastni razredi implementirajo vmesnike SPL.

CLI - vmesnik ukazne vrstice

PHP je bil narejen za ustvarjanje spletnih aplikacij, vendar je uporaben tudi za skriptiranje programov vmesnika ukazne vrstice (CLI - command line interface). Programi PHP za ukazno vrstico lahko pomagajo avtomatizirati pogoste naloge, kot so testiranje, nalaganje in administriranje aplikacije.

Programi CLI PHP so zmogljivi, saj lahko uporabite kodo vaše aplikacije direktno brez potrebe po ustvarjanju in zavarovanju spletnega GUI-ja zanjo. Bodite samo pazljivi, da ne date vašega skripta PHP CLI v vaš javni spletni direktorij!

Poskusite pognati PHP iz ukazne vrstice:

> php -i

Opcija -i bo izpisala vašo konfiguracijo PHP tako kot funkcija phpinfo().

Opcija -a ponuja interaktivno lupino, podobno kot Rubyjev IRB ali Pythonova interaktivna lupina. Na voljo je še mnogo ostalih uporabnih možnosti ukazne vrstice.

Napišimo preprost program CLI »Hello, $name«. Da ga preizkusite, ustvarite datoteko poimenovano hello.php, tako kot je prikazano spodaj.

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

PHP priredi dve posebni spremenljivki, ki temeljita na podanih argumentih pri pogonu vašega skripta. $argc je celo številska spremenljivka, ki vsebuje argument count, in $argv je spremenljivka tipa polje, ki vsebuje vrednost vsakega argumenta. Prvi argument je vedno ime vaše skriptne datoteke PHP, v tem primeru hello.php.

Izraz exit() je uporabljen s vrednostjo različno od nič, da omogoči lupini vedeti, da je ukaz spodletel. Pogosto uporabljene izhodne kode je moč najti tu.

Za pogon našega skripta zgoraj iz ukazne vrstice:

> php hello.php
Usage: php hello.php <name>
> php hello.php world
Hello, world

Xdebug

Eno najuporabnejših orodij v razvijanju programske opreme je ustrezen iskalnik napak. Omogoča sledenje izvajanja vaše kode in nadzira vsebino skladovnice. Xdebug, PHP-jev iskalnik napak, je lahko izkoriščen s strani različnih IDE-jev, ki ponujajo prekinitvene točke in nadzor skladovnice. Lahko dovoli tudi orodjem, kot sta PHPUnit in KCacheGrind, da izvedejo analizo pokritosti kode in profiliranje kode.

Če se vidite v taki navezavi, da se obračate k var_dump()/print_r() in še vedno ne najdete rešitve - morda potrebujete iskalnik napak.

Namestitev Xdebuga je lahko zahtevna, vendar je ena izmed njegovih najpomembnejših lastnosti t. i. oddaljeno iskanje napak (angl. remote debugging) - če razvijate kodo lokalno in jo nato testirate znotraj virtualne naprave ali drugega strežnika, je oddaljeno iskanje napak lastnost, ki jo želite omogočiti takoj.

Običajno boste spremenili vaš Apache VHost ali datoteko .htaccess s sledečimi vrednostmi:

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

Lastnosti “remote host” in “remote port” bosta pripadali vašemu lokalnemu računalniku in nastavljenim vratom, ki jih posluša vaš IDE. Nato je samo še stvar nastavitve vašega IDE-ja, da “posluša” povezave in naloži URL:

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

Vaš IDE bo prestrezal trenutno stanje, ko se skript izvaja, dovoljuje vam, da ustvarite prekinitvene točke in preveri vrednosti v spominu.

Grafični iskalniki napak omogočajo zelo enostavno prehajanje skozi kodo, preverjanje spremenljivk in ocenjujejo kodo napram zagonu v živo. Mnogi IDE-ji imajo vgrajeno ali na vtičniku osnovano podporo za grafično iskanje napak z Xdebugom. MacGDBp je brezplačen, odprtokodni, samostojni Xdebug GUI za macOS.

Nazaj na vrh

Upravljanje odvisnosti

Na izbiro je ogromno knjižnic PHP, ogrodij in komponent. Vaš projekt bo najverjetneje uporabil več njih - to so t. i. projektne odvisnosti. Do pred kratkim PHP ni imel dobrega načina za upravljanje teh projektnih odvisnosti. Tudi če ste jih upravljali ročno, ste morali še vedno skrbeti za avtomatske nalagalnike (autoloaders). To ni več težava.

Trenutno sta za PHP na voljo dva glavna paketna upravljalca - Composer in PEAR. Composer je trenutno najpopularnejši upravitelj paketov za PHP, vendar dolgo časa je bil v uporabi glavni upravitelj paketov PEAR. Poznavanje zgodovine PEAR je dobra ideja, saj še vedno najdete sklicevanje nanj, tudi če ga nikoli ne uporabljate.

Composer in Packagist

Composer je priporočeni upravljalnik odvisnosti za PHP. Napišite vaše projektne odvisnosti v datoteko composer.json in z nekaj enostavnimi ukazi bo Composer avtomatsko prenesel odvisnosti za vaš projekt in nastavil avtomatsko nalaganje (angl. autoloading) za vas. Composer je analogen NPM-ju v svetu Node.js ali Bundlerju v svetu Ruby.

Na voljo je obilica knjižnic PHP, ki so kompatibilne s Composerjem in pripravljene za uporabo v vašem projektu. Ti “paketi” so našteti na [Packagistu], uradnem repozitoriju za Composer-kompatibilne knjižnice PHP.

Kako namestiti Composer

Najbolj varen način za namestitev Composerja je slediti uradnim navodilom. To zagotovi, da namestitveni program ni pokvarjen ali ponarejen. Namestitveni program namesti binarni skript composer.phar v vaš trenutni delovni direktorij.

Composer priporočamo namestiti globalno (npr. v /usr/local/bin). Da to naredite, poženite naslednji ukaz:

mv composer.phar /usr/local/bin/composer

Opomba: Če zgornje ni uspešno zaradi pravic, poženite ponovno s sudo.

Da poženete lokalno nameščen Composer, bi uporabili php composer.phar, globalno pa je enostavno composer.

Namestitev na Windows

Za uporabnike Windows je najenostavnejši način za pričetek uporaba namestitvenega programa ComposerSetup, ki izvede globalno namestitev in nastavi vašo $PATH, da lahko samo pokličete composer iz kateregakoli direktorija v vaši ukazni vrstici.

Kako definirati in namestiti odvisnosti

Composer beleži odvisnosti vašega projekta v datoteki imenovani composer.json. Če želite, jo lahko upravljate ročno, ali pa uporabite sam Composer. Ukaz composer require doda odvisnost projekta in če nimate composer.json datoteke, bo ustvarjena. Spodaj je primer, ki doda Twig kot odvisnost v vaš projekt.

composer require twig/twig:^2.0

Alternativno, ukaz composer init vas bo vodil skozi ustvarjanje celotne datoteke composer.json za vaš projekt. Ko enkrat ustvarite vašo datoteko composer.json lahko poveste Composerju, da prenese in namesti vaše odvisnosti v direktorij vendor/. To velja tudi za projekte, ki ste jih prenesli in že vsebujejo datoteko composer.json:

composer install

V nadaljevanju dodajte naslednjo vrstico v vašo glavno datoteko aplikacije PHP. To narekuje PHP-ju, da uporabi Composerjev avtomatski nalagalnik (angl. autoloader) za odvisnosti vašega projekta.

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

Sedaj lahko uporabite odvisnosti vašega projekta in bodo avtomatsko naložene na zahtevo.

Posodobitev vaših odvisnosti

Composer ustvari datoteko imenovano composer.lock, ki shrani točno različico za vsak paket, ki ga je prenesel, ko ste prvič pognali ukaz composer install. Če delite vaš projekt z drugimi, zagotovite, da je datoteka composer.lock vključena, tako da bodo ob ukazu composer install dobili enake različice kot vi. Za posodobitev vaših odvisnosti poženite ukaz composer update. Ne uporabljajte composer update, ko nalagate aplikacijo na strežnik. Takrat poženite samo composer install, drugače boste lahko imeli drugačne različice paketov v produkciji.

To je najbolj uporabno, ko definirate vaše različice zahtev fleksibilno. Na primer zahtevana različica ~1.8 pomeni »karkoli novejše od 1.8.0, vendar manjše od 2.0.x-dev«. Lahko uporabite tudi maskirni znak * kot pri 1.8.*. Sedaj bo ukaz Composer php composer.phar update nadgradil vse vaše odvisnosti na najnovejše različice, ki ustrezajo omejitvam, ki ste jih definirali.

Obvestila posodobitev

Da dobite obvestila o novih različicah izdaj se lahko naročite na spletno storitev libraries.io, ki nadzira odvisnosti in pošilja e-pošto z novimi izdajami paketov.

Preverjanje vaših odvisnosti za varnostnimi težavami

Local PHP Security Checker je orodje za ukazno vrstico (CLI), ki bo preučilo vašo datoteko composer.lock in vam izpisalo, če potrebujete kakšne posodobitve za vaše odvisnosti.

Upravljanje globalnih odvisnosti s Composerjem

Composer lahko upravlja tudi globalne odvisnosti in njihove zagonske datoteke. Uporaba je enostavna, vse kar morate narediti je, da dodate vašim ukazom predpono global. Če na primer želite namestiti PHPUnit in ga imeti na voljo globalno, poženite naslednji ukaz:

composer global require phpunit/phpunit

To bo ustvarilo mapo ~/.composer, kjer bodo domovale vaše globalne odvisnosti. Da imate nameščene paketne zagonske datoteke in so na voljo kjerkoli, bi potem dodali ~/.composer/vendor/bin k vaši spremenljivki $PATH.

PEAR

Veteranski upravljalnik paketov, ki ga imajo radi nekateri razvijalci PHP, je PEAR. Obnaša se podobno kot Composer, vendar ima nekatere opazne razlike.

PEAR zahteva, da ima vsak paket specifično strukturo, kar pomeni, da mora avtor pripraviti paket za uporabo s PEAR. Uporaba projekta, ki ni bil pripravljen za delo s PEAR, ni možna.

PEAR namesti pakete globalno, kar pomeni, da so po prvi namestitvi na voljo za vse projekte na tem strežniku. To je lahko uporabno, če se veliko projektov zanaša na enak paket z enako različico, vendar lahko vodi do problemov, če se različici med dvema projektoma ne ujemata.

Kako namestiti PEAR

PEAR lahko namestite s prenosom namestitvenega programa .phar in zagonom le tega. Dokumentacija PEAR ima podrobna navodila namestitve za vsak operacijski sistem.

Če uporabljate Linux, lahko pogledate tudi vaš distribucijski upravljalnik paketov. Debian in Ubuntu na primer, imata paket apt php-pear.

Kako namestiti paket

Če je paket naveden na seznamu paketov PEAR, ga lahko namestite z določitvijo uradnega imena:

pear install foo

Če paket gostuje na drugem kanalu, morate najprej odkriti (discover) kanal in ga nato določiti pri namestitvi. Poglejte dokumentacijo uporabe kanalov za več informacij na to temo.

Ravnanje z odvisnostmi PEAR preko Composerja

Če že uporabljate Composer in bi želeli namestiti še nekaj kode PEAR, lahko uporabite Composer, da upravlja z vašimi odvisnostmi PEAR. Repozitoriji PEAR niso več direktno podprti s strani različice Composer 2, tako da morate ročno dodati repozitorij za namestitev paketov PEAR:

{
    "repositories": [
        {
            "type": "package",
            "package": {
                "name": "pear2/pear2-http-request",
                "version": "2.5.1",
                "dist": {
                    "url": "https://github.com/pear2/HTTP_Request/archive/refs/heads/master.zip",
                    "type": "zip"
                }
            }
        }
    ],
    "require": {
        "pear2/pear2-http-request": "*"
    },
    "autoload": {
        "psr-4": {"PEAR2\\HTTP\\": "vendor/pear2/pear2-http-request/src/HTTP/"}
    }
}

Prva sekcija "repositories" bo uporabljena, da Composerju sporoči, da mora inicializirati (ali odkriti - angl. discover v terminologiji PEAR-a) repozitorij PEAR. Nato bo sekcija require naredila predpone paketom na naslednji način:

pear-channel/package

Predpona »pear« je zakodirana, da ne prihaja do konfliktov, saj je kanal PEAR lahko enak kot drugo ime izdelovalca paketov na primer. Takrat je lahko uporabljeno kratko ime kanala (oz. celotni URL) za referenco na katerem kanalu je paket.

Ko je ta koda nameščena, bo na voljo v vašem direktoriju izdelovalcev (vendor) in bo avtomatsko na voljo skozi Composerjev avtomatski nalagalnik (angl. autoloader).

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

Za uporabo tega paketa PEAR se nanj enostavno sklicujete takole:

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

use PEAR2\HTTP\Request;

$request = new Request();

Nazaj na vrh

Kodne prakse

Osnove

PHP je širok jezik, ki dovoljuje razvijalcem vseh nivojev zmožnost, da sproducirajo kodo ne samo hitro, vendar tudi efektivno. Vendar kljub napredku skozi jezik pogostokrat pozabimo osnove, ki se jih naučimo na začetku (ali jih spregledamo) zaradi hitrih izrezov in/ali slabih navad. Za pomoč pri tej običajni problematiki ta sekcija cilja k opominjanju razvijalcev o osnovnih kodnih praksah znotraj PHP-ja.

Datum in čas

PHP ima razred DateTime, ki pomaga, ko berete, pišete, primerjate ali računate z datumi in časi. V PHP-ju je na voljo mnogo funkcij, ki se nanašajo na datum in čas poleg razreda DateTime, vendar le-ta ponuja ličen objektno orientiran vmesnik za večino najpogostejših primerov uporabe. DateTime omogoča ravnanje s časovnimi območji, vendar to je izven obsega te kratke predstavitve.

Za pričetek dela z DateTime, pretvorimo izvorni niz datuma in časa v objekt s tovarniško metodo createFromFormat(), ali pa uporabimo new DateTime, da dobimo trenuten datum in čas. Uporabite metodo format() za pretvorbo DateTime nazaj v niz za izpis.

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

echo 'Start date: ' . $start->format('Y-m-d') . PHP_EOL;

Računanje z DateTime je možno s pomočjo razreda DateInterval. DateTime ima metode, kot so add() in sub(), ki sprejmejo DateInterval kot argument. Ne pišite kode, ki pričakuje enako število sekund v vsakem dnevu. Namreč poletni čas in spreminjanje časovnih območij bosta tako pokvarila to predpostavko. Namesto tega uporabite intervale datumov. Za izračun sprememb datuma uporabite metodo diff(). Vrnila bo nov DateInterval, ki je izjemno enostaven za prikaz.

<?php
// create a copy of $start and add one month and 6 days
$end = clone $start;
$end->add(new DateInterval('P1M6D'));

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

Na objektih DateTime lahko uporabite standardne primerjave:

<?php
if ($start < $end) {
    echo "Start is before the end!" . PHP_EOL;
}

Zadnji primer prikazuje razred DatePeriod. Uporabljen je za iteracijo nad ponavljajočimi se dogodki. Vzame lahko dva objekta DateTime, začetek in konec ter interval, za katerega vrne vse vmesne dogodke.

<?php
// output all thursdays between $start and $end
$periodInterval = DateInterval::createFromDateString('first thursday');
$periodIterator = new DatePeriod($start, $periodInterval, $end, \DatePeriod::EXCLUDE_START_DATE);
foreach ($periodIterator as $date) {
    // output each date in the period
    echo $date->format('Y-m-d') . ' ';
}

Popularna razširitev PHP API je Carbon. Podeduje vse iz razreda DateTime, tako da vključuje minimalno število sprememb kode, dodatne lastnosti pa vključujejo podporo za lokalizacijo, nadaljnje načine za dodajanje, odštevanje in oblikovanje objekta DateTime ter sredstva za testiranje vaše kode s simuliranjem datuma in časa po izbiri.

Načrtovalski vzorci

Ko gradite vašo aplikacijo, pomaga uporabiti pogoste vzorce v vaši kodi in pogoste vzorce za celotno strukturo vašega projekta. Uporaba pogostih vzorcev pomaga poenostaviti upravljanje vaše kode in omogoča ostalim razvijalcem hitro razumeti, kako se vse skupaj ujema.

Če uporabljate ogrodje, potem bo večina višje nivojske kode in projektne strukture osnovana na tem ogrodju, tako da je veliko odločitev vzorcev že urejenih za vas. Vendar je pa še vedno na vas, da izberete najboljše vzorce, ki jim boste sledili v kodi, ki jo gradite na osnovi ogrodja. Po drugi strani, če ne uporabljate ogrodja za grajenje vaše aplikacije, potem morate najti vzorce, ki najbolje zadostijo tipu in velikosti aplikacije, ki jo gradite.

Več o načrtovalskih vzorcih PHP in primerih uporabe lahko izveste na:

Delo z UTF-8

To sekcijo je prvotno napisal Alex Cabal na PHP Best Practices in je uporabljena kot osnova za naš lasten UTF-8 nasvet.

Tu ni ene vrstice. Bodite previdni, pozorni na podrobnosti in skladni.

Trenutno PHP ne podpira Unicode na nižjem nivoju. Obstajajo načini za zagotovitev, da so nizi UTF-8 ustrezno procesirani, vendar to ni enostavno in zahteva posvečanje na skoraj vseh nivojih spletne aplikacije, od HTML, do SQL, do PHP. Ciljali bomo na kratek in praktičen povzetek.

UTF-8 na nivoju PHP

Osnovne operacije nizov, kot sta združevanje dveh nizov in dodeljevanje nizov spremenljivkam, ne potrebujejo ničesar posebnega za UTF-8. Vendar večina funkcij nizov, kot sta strpos() in strlen(), ne potrebuje posebnih premislekov. Te funkcije imajo pogosto nadomestke mb_*: na primer mb_strpos() in mb_strlen(). Ti mb_* nizi so na voljo za vas preko razširitve niza multibyte in so posebej načrtovani za operiranje na nizih Unicode.

Kadarkoli izvajate operacije na nizih Unicode, morate uporabljati funkcije mb_*. Na primer, če uporabljate substr() na nizu UTF-8, je precejšnja verjetnost, da bo rezultat vključeval popačene polovične znake. Pravilna funkcija za uporabo bi bila večbajtni nadomestek mb_substr().

Težji del v vseh primerih si je zapomniti uporabo funkcij mb_*. Če samo enkrat pozabite, bo vaš niz Unicode zelo verjetno popačen med naslednjim procesiranjem.

Nadomestka mb_* nimajo vse funkcije nizov. Če določene funkcije ni na voljo, kar želite narediti, potem lahko nimate sreče.

Uporabljati bi morali funkcijo mb_internal_encoding() na vrhu vsakega skripta PHP, ki ga napišete (ali na vrhu vašega globalnega skripta include), in funkcijo mb_http_output() ravno za njo, če vaša skripta izpisuje brskalniku. Izrecno definiranje kodiranja vašega niza v vsakem skriptu vam bo prihranilo veliko glavobolov tekom poti.

Dodatno ima mnogo funkcij PHP, ki operirajo na nizih, opcijske parametre, ki vam omogočajo specifikacijo kodiranja znakov. Vedno bi morali eksplicitno navesti UTF-8, ko imate možnost. Na primer, htmlentites() ima možnost za kodiranje znakov in morali bi vedno določiti UTF-8, če imate opravka s takimi nizi. Bodite pozorni, da od PHP 5.4.0 je UTF-8 privzeto kodiranje za htmlentities() in htmlspecialchars().

Na koncu, če gradite distribuirano aplikacijo in ne morete vedeti, ali bo razširitev mbstring omogočena, potem premislite o uporabi Composerjevega paketa symfony/polyfill-mbstring. Ta bo uporabil mbstring, če je na voljo in se vrnil na funkcije brez UTF-8, če ni.

UTF-8 na nivoju podatkovne baze

Če vaš skript PHP dostopa do MySQL-a, obstaja verjetnost, da so vaši nizi v podatkovni bazi shranjeni kot nizi brez UTF-8, tudi če sledite vsem varnostnim ukrepom zgoraj.

Da zagotovite, da gredo vaši nizi iz PHP-ja v MySQL kot UTF-8, zagotovite, da so vaša podatkovna baza in vse tabele nastavljene na nabor znakov in kolacijo utf8mb4 ter da uporabljate nabore znakov utf8mb4 v nizu povezave PDO. Glejte primer kode spodaj. To je kritično pomembno.

Pomnite, da morate uporabiti nabor znakov utf8mb4 za celotno podporo UTF-8 in ne nabora znakov utf8! Glejte nadaljnje branje spodaj zakaj.

UTF-8 na nivoju brskalnika

Uporabite funkcijo mb_http_output() za zagotovitev, da vaš skript PHP izpisuje nize UTF-8 v vaš brskalnik.

Brskalniku bo nato povedano s strani odziva HTTP, da bi ta stran morala biti smatrana kot UTF-8. Dandanes je pogosta uporaba nastavitve nabora znakov v glavi odziva HTTP:

<?php
header('Content-Type: text/html; charset=UTF-8')

Zgodovinski pristop za to je bilo vključiti značko charset <meta> v značko <head> vaše strani.

<?php
// Tell PHP that we're using UTF-8 strings until the end of the script
mb_internal_encoding('UTF-8');
$utf_set = ini_set('default_charset', 'utf-8');
if (!$utf_set) {
    throw new Exception('could not set default_charset to utf-8, please ensure it\'s set on your system!');
}

// Tell PHP that we'll be outputting UTF-8 to the browser
mb_http_output('UTF-8');

// Our UTF-8 test string
$string = 'Êl síla erin lû e-govaned vîn.';

// Transform the string in some way with a multibyte function
// Note how we cut the string at a non-Ascii character for demonstration purposes
$string = mb_substr($string, 0, 15);

// Connect to a database to store the transformed string
// See the PDO example in this document for more information
// Note the `charset=utf8mb4` v DSN (Data Source Name)
$link = new PDO(
    'mysql:host=your-hostname;dbname=your-db;charset=utf8mb4',
    'your-username',
    'your-password',
    array(
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
        PDO::ATTR_PERSISTENT => false
    )
);

// Store our transformed string as UTF-8 in our database
// Your DB and tables are in the utf8mb4 character set and collation, right?
$handle = $link->prepare('insert into ElvishSentences (Id, Body, Priority) values (default, :body, :priority)');
$handle->bindParam(':body', $string, PDO::PARAM_STR);
$priority = 45;
$handle->bindParam(':priority', $priority, PDO::PARAM_INT); // explicitly tell pdo to expect an int
$handle->execute();

// Retrieve the string we just stored to prove it was stored correctly
$handle = $link->prepare('select * from ElvishSentences where Id = :id');
$id = 7;
$handle->bindParam(':id', $id, PDO::PARAM_INT);
$handle->execute();

// Store the result into an object that we'll output later in our HTML
// This object won't kill your memory because it fetches the data Just-In-Time to
$result = $handle->fetchAll(\PDO::FETCH_OBJ);

// An example wrapper to allow you to escape data to html
function escape_to_html($dirty){
    echo htmlspecialchars($dirty, ENT_QUOTES, 'UTF-8');
}

header('Content-Type: text/html; charset=UTF-8'); // Unnecessary if your default_charset is set to utf-8 already
?><!doctype html>
<html>
    <head>
        <title>UTF-8 test page</title>
    </head>
    <body>
        <?php
        foreach($result as $row){
            escape_to_html($row->Body);  // This should correctly output our transformed UTF-8 string to the browser
        }
        ?>
    </body>
</html>

Nadaljnje branje

Jezikovno prilagajanje oz. i18n (angl. internationalization) in krajevno prilagajanje oz. l10n (angl. localization)

Opozorilo za novince: i18n in l10n sta t. i. numeronima, neke vrste kratici, kjer se številke uporabljajo za skrajšanje besede - v našem primeru, internationalization postane i18n in localization, l10n.

Najprej moramo opredeliti ta dva podobna koncepta in druge s tem povezane stvari:

Pogosti načini za izvajanje

Najenostavnejši način za jezikovno prilaganje programske opreme PHP, je uporaba datotek polj in uporaba teh nizov v predlogah, kot je <h1><?=$TRANS['title_about_page']?></h1>. To drugače ni priporočljiv način za resnejše projekte, saj predstavlja nekatera vprašanja glede vzdrževanja - nekatera se lahko pojavijo na samem začetku, kot je pluralizacija. Torej, ne poskušajte tega, če bo vaš projekt vseboval več kot nekaj strani.

Najbolj klasičen način in pogosto vzet kot referenca za i18n in l10n je orodje za Unix, imenovano gettext. Izvira nazaj iz leta 1995 in je še vedno popolna izvedba za prevajanje programske opreme. Zelo enostavno ga je postaviti, medtem ko še vedno omogoča močna podporna orodja. Podrobneje bomo o Gettext govorili spodaj. Če bi se želeli izogniti uporabi ukazne vrstice, bomo predstavili odlično aplikacijo GUI, ki se jo lahko uporablja za enostavno posodobitev virov datotek l10n.

Druga orodja

Obstajajo skupne knjižnice, ki se uporabljajo za podporo Gettext in drugih implementacij i18n. Nekatere izmed njih se lažje namestijio ali pa prikazujejo dodatne funkcionalnosti ali formate datotek i18n. V tem dokumentu, se bomo osredotočili na orodja, podprta v jedru PHP, vendar tu je seznam drugih za celovitost:

Druga ogrodja vključujejo tudi module i18n, vendar niso na voljo izven njihove kodne osnove:

Če se odločite uporabiti eno od knjižnic, ki ne ponuja izvlečkov, boste morda želeli uporabiti oblike gettext, tako da lahko uporabite prvotni skupek orodij gettext (vključno s Poedit), kot je opisano v preostalem delu poglavja.

Gettext

Namestitev

Morda boste morali namestiti Gettext in s tem povezano knjižnico PHP z upraviteljem paketov, kot sta apt-get ali yum. Po namestitvi jo omogočite z extension=gettext.so (Linux/Unix) ali extension=php_gettext.dll (Windows) v vaši datoteki php.ini.

Tu bomo uporabili tudi Poedit za ustvarjanje datotek prevodov. Verjetno ga boste našli v upravitelju paketov vašega sistema; na voljo je za Unix, macOS in Windows. Lahko se ga tudi brezplačno prenese iz njihove spletne strani.

Struktura

Vrste datotek

Obstajajo tri datoteke, ki se običajno obravnavajo pri delu z Gettextom. Glavne med njimi so datoteke PO (angl. portable object) in MO (angl. machine object), pri čemer je prva seznam berljivih »prevedenih objektov« in druga ustreza binarni interpretaciji z gettext, ko izvaja krajevno prilagajanje. Na voljo je tudi datoteka POT (predloga), ki preprosto vsebuje vse obstoječe ključe iz izvornih datotek in se lahko uporabi kot vodilo za ustvarjanje in posodobitev vseh datotek PO. Tiste datoteke predlog niso obvezne: odvisno od orodja, ki ga uporabljate za l10n, lahko popolnoma primerno uporabite tudi samo datoteke PO/MO. Vedno boste imeli par datotek PO/MO glede na jezik in regijo, ampak le eno datoteko POT na domeno.

Domene

Obstajajo nekateri primeri velikih projektov, kjer boste morda morali ločiti prevode, ko enake besede izražajo različen pomen glede na kontekst. V teh primerih jih ločite v različne domene. To so v bistvu imenske skupine datotek POT/PO/MO, kjer je omenjena datoteka domena prevoda. Majhni in srednje veliki projekti običajno zaradi enostavnosti uporabljajo samo eno domeno; njeno ime je poljubno, vendar mi bomo uporabljali »main« za naše vzorce kode. V projektih Symfony, na primer, se domene uporabljajo za ločevanje prevoda od sporočil potrjevanja.

Koda področnih nastavitev

Področne nastavitve so enostavno koda, ki označuje določeno različico jezika. To je opredeljeno po specifikacijah ISO 639-1 in ISO 3166-1 alpha-2: dve mali črki za jezik, ki jima opcijsko sledi podčrtaj in dve veliki črki, ki označujeta državo ali območno kodo. Za redke jezike se uporabijo tri črke.

Za določene govorce je lahko del države odveč. V bistvu, imajo nekateri jeziki narečja v različnih državah, kot sta avstrijska nemščina (de_AT) ali brazilska portugalščina (pt_BR). Drugi del se uporablja za razlikovanje med temi narečji - ko ga ni, je to sprejeto kot »generična« ali »hibridna« različica jezika.

Struktura direktorijev

Za uporabo Gettext, bomo morali upoštevati posebno strukturo direktorijev. Najprej, boste morali izbrati poljubni vrhnji direktorij za datoteke l10n v vašem izvornem repozitoriju. V njem boste imeli mapo za vsako potrebno področno nastavitev in fiksno mapo LC_MESSAGES, ki bo vsebovala vse vaše pare PO/MO. Na primer:

<project root>
 ├─ src/
 ├─ templates/
 └─ locales/
    ├─ forum.pot
    ├─ site.pot
    ├─ de/
    │  └─ LC_MESSAGES/
    │     ├─ forum.mo
    │     ├─ forum.po
    │     ├─ site.mo
    │     └─ site.po
    ├─ es_ES/
    │  └─ LC_MESSAGES/
    │     └─ ...
    ├─ fr/
    │  └─ ...
    ├─ pt_BR/
    │  └─ ...
    └─ pt_PT/
       └─ ...

Oblike množin

Kot smo povedali v uvodu, imajo lahko različni jeziki različna pravila množine. Vendar gettext nam pomaga tudi pri tem. Pri ustvarjanju nove datoteke .po, boste morali določiti pravila množine za ta jezik in prevedeni deli, ki so odvisni od množine, bodo imeli drugačne oblike za vsako od teh pravil. Ko kličete Gettext v kodi, boste morali določiti število povezano s stavkom in to bo uporabilo pravilno obliko - tudi pri uporabi menjave niza, če je potrebno.

Pravila množine vključujejo število množin, ki so na voljo, in logični test z n, ki bi opredelil, v katero pravilo spada določeno število (začne se z 0). Na primer:

Sedaj ko razumete osnovo, kako pravila množin delujejo - drugače si poglejte podrobnejše razlage na vodičih LingoHub -, boste morda želeli kopirati tiste, ki jih potrebujete iz seznama namesto, da jih pišete ročno.

Ko se kliče Gettext, da naredi krajevno prilagajanje na stavkih s števci, boste morali podati tudi povezano številko. Gettext bo določil, katero pravilo bi moralo biti v veljavi in uporabil bo pravilno krajevno različico. Za vsako definirano pravilo množine boste morali dodati drugačen stavek v datoteke .po.

Primer izvedbe

Po vsej tej teoriji naredimo nekaj praktičnega. Tukaj je odlomek iz datoteke .po - njena oblika ni pomembna. Pomembna je celotna vsebina. Kako jo urediti, se boste enostavno naučili kasneje:

msgid ""
msgstr ""
"Language: pt_BR\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"

msgid "We're now translating some strings"
msgstr "Nós estamos traduzindo algumas strings agora"

msgid "Hello %1$s! Your last visit was on %2$s"
msgstr "Olá %1$s! Sua última visita foi em %2$s"

msgid "Only one unread message"
msgid_plural "%d unread messages"
msgstr[0] "Só uma mensagem não lida"
msgstr[1] "%d mensagens não lidas"

Prvi del deluje kot glava, ki ima msgid in msgstr prazna. Opisuje kodiranje datoteke, oblike množine in druge manj pomembne stvari. Drugi del prevaja enostaven niz iz angleščine v brazilsko portugalščino in tretji počne isto, vendar zamenjuje niz iz sprintf, tako da prevod lahko vsebuje uporabniško ime in datum obiska. Zadnji del je primer oblik množin in prikazuje verzijo ednine in množine kot msgid v angleščini in njene ustrezne prevode kot msgstr 0 in 1 (sledi številka pravila množine). Zamenjani niz je tudi uporabljen, da je število razvidno neposredno v stavku, s pomočjo %d. Oblike množine imajo vedno dva msgid (ednino in množino), tako da ni priporočljivo uporabljati kompleksnega jezika za vir prevoda.

Razprava glede ključev l10n

Kot ste morda opazili, uporabljamo za izvorni ID dejanski stavek v angleščini. Tisti msgid je enak, kot je uporabljen v vseh datotekah .po, kar pomeni, da bodo drugi jeziki imeli enako obliko in enaka polja msgid, vendar prevedene vrstice msgstr.

Za ključe prevodov obstajata dva glavna načina:

  1. msgid kot celoten stavek. Glavne prednosti so:
    • Če obstajajo neprevedeni deli programske opreme za katerikoli jezik, bo prikazani ključ še vedno ohranil nekaj pomena. Primer: prevajanje iz angleščine v španščino, vendar potrebujete pomoč pri prevajanju v francoščino, boste morda objavili novo stran z manjkajočimi francoskimi prevodi. V tem primeru bodo deli spletne strani prikazani v angleščini;
    • Prevajalcu je veliko enostavnejše razumeti, kaj se dogaja in podati ustrezni prevod, ki temelji na msgid;
    • Privzeto je l10n za enega od jezikov tako že podan;
    • Edina slabost: če želite spremeniti dejansko besedilo, bo potrebno zamenjati ta msgid v več jezikovnih datotekah.
  2. msgid kot unikaten, strukturiran ključ. Namesto stavka se tu uporabi strukturiran način, vključno s predlogi ali deli, kjer se določen niz nahaja.
    • To je odličen način imeti kodo organizirano in ločiti besedilo vsebine od logike predloge.
    • Vseeno to lahko prinese težave prevajalcu, če spregleda kontekst. Izvorna jezikovna datoteka je potrebna kot osnova za druge prevode. Primer: razvijalec bi v najboljšem primeru imel datoteko en.po, ki jo prevajalci uporabijo za prevajanje v datoteki npr. fr.po.
    • Manjkajoči prevodi prikažejo nesmiselne ključe (top_menu.welcome namesto Pozdravljeni, uporabnik! na omenjeni neprevedeni francoski strani). To je do določene mere prednost, saj motivira prevajalca za popolno objavo. Slabost pa je, da težave pri prevodih izgledajo res grdo v vmesniku. Nekatere knjižnice imajo tudi možnost, da opredelijio določen jezik kot »nadomestni« in se uporabi v primeru manjkajočega prevoda.

Navodila Gettext dajejo prednost prvemu pristopu, kot splošnemu, saj je lažji prevajalcem in uporabnikom v primeru težav. Tako bomo delali tudi v sledečih primerih. Drugače dokumentacija Symfony daje prednost ključnim besedam, kar omogoča neodvisne spremembe vseh prevodov, ne da bi to vplivalo na predloge.

Vsakdanja uporaba

V pogosto uporabljani aplikaciji, bi uporabili nekatere funkcije Gettext za pisanje statičnih tekstov na vaših straneh. Te stavki bi se potem pojavili v datotekah .po, se prevedli in se prevedli v datoteke .mo. Nato jih Gettext uporabi pri upodabljanju dejanskega vmesnika. Glede na to povežimo skupaj, kar smo doslej razpravljali, v primer korak za korakom:

1. Primer datoteke predloge, ki vključuje nekaj različnih klicev Gettext

<?php include 'i18n_setup.php' ?>
<div id="header">
    <h1><?=sprintf(gettext('Welcome, %s!'), $name)?></h1>
    <!-- code indented this way only for legibility -->
    <?php if ($unread): ?>
        <h2><?=sprintf(
            ngettext('Only one unread message',
                     '%d unread messages',
                     $unread),
            $unread)?>
        </h2>
    <?php endif ?>
</div>

<h1><?=gettext('Introduction')?></h1>
<p><?=gettext('We\'re now translating some strings')?></p>

2. Primer namestitvene datoteke (i18n_setup.php, kot je uporabljeno zgoraj), izbira pravilnih področnih nastavitev ter nastavitev Gettexta

<?php
/**
 * Verifies if the given $locale is supported in the project
 * @param string $locale
 * @return bool
 */
function valid($locale) {
    return in_array($locale, ['en_US', 'en', 'pt_BR', 'pt', 'es_ES', 'es']);
}

//setting the source/default locale, for informational purposes
$lang = 'en_US';

if (isset($_GET['lang']) && valid($_GET['lang'])) {
    // the locale can be changed through the query-string
    $lang = $_GET['lang'];    //you should sanitize this!
    setcookie('lang', $lang); //it's stored in a cookie so it can be reused
} elseif (isset($_COOKIE['lang']) && valid($_COOKIE['lang'])) {
    // if the cookie is present instead, let's just keep it
    $lang = $_COOKIE['lang']; //you should sanitize this!
} elseif (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
    // default: look for the languages the browser says the user accepts
    $langs = explode(',', $_SERVER['HTTP_ACCEPT_LANGUAGE']);
    array_walk($langs, function (&$lang) { $lang = strtr(strtok($lang, ';'), ['-' => '_']); });
    foreach ($langs as $browser_lang) {
        if (valid($browser_lang)) {
            $lang = $browser_lang;
            break;
        }
    }
}

// here we define the global system locale given the found language
putenv("LANG=$lang");

// this might be useful for date functions (LC_TIME) or money formatting (LC_MONETARY), for instance
setlocale(LC_ALL, $lang);

// this will make Gettext look for ../locales/<lang>/LC_MESSAGES/main.mo
bindtextdomain('main', '../locales');

// indicates in what encoding the file should be read
bind_textdomain_codeset('main', 'UTF-8');

// if your application has additional domains, as cited before, you should bind them here as well
bindtextdomain('forum', '../locales');
bind_textdomain_codeset('forum', 'UTF-8');

// here we indicate the default domain the gettext() calls will respond to
textdomain('main');

// this would look for the string in forum.mo instead of main.mo
// echo dgettext('forum', 'Welcome back!');
?>

3. Priprava prevodov

Da naredimo zadeve enostavnejše - ena izmed večjih prednosti Gettexta pred paketi ogrodij i18n je njegov tip datoteke po meri. »Oh, človek, to je zelo težko razumeti in ročno urejati. Enostavno polje nizov je enostavnejše!« Ne naredite napake, aplikacije, kot je Poedit, so tu v pomoč - veliko pomoč. Program lahko dobite iz njihove spletne strani, je brezplačen in na voljo za vse platforme. Je orodje, ki je zelo enostavno za privaditi se, in hkrati zelo močno - uporaba vseh zmogljivih funkcij, ki jih ima Gettext na voljo.

V prvem zagonu morate iz menija izbrati »File > New Catalog«. Tam bo majhen zaslon, kjer bomo določili podatke, da bo vse ostalo gladko teklo. Te nastavitve boste lahko našli pozneje prek »Catalog > Properties«:

Po nastavitvi teh točk boste pozvani, da shranite datoteko - z uporabo datotečne strukture, ki smo jo omenili zgoraj, nato pa se bo izvedlo skeniranje izvornih datotek, da se najde klice krajevnega prilagajanja. V tabelo za prevajanje bodo novi vnosi podani kot prazni in začeli boste lahko vpisovati krajevne različice teh nizov. Shranite jih in datoteka .mo bo ponovno prevedena v istem direktoriju. Tako je vaš projekt sedaj internacionaliziran.

4. Prevajanje nizov

Kot ste morda prej opazili, obstajata dve glavni vrsti krajevno prilagojenih nizov: enostavni in tisti z oblikami množine. Prvi imajo le dve okenci: vir in lokaliziran niz. Izvornega niza ni mogoče spreminjati, saj Gettext/Poedit ne vključujeta funkcionalnosti spreminjanja izvornih datotek - spremeniti morate sam vir in znova preveriti datoteke. Nasvet: desni klik vrstice prevoda bo prikazal namig o izvorni datoteki in vrsticah, kjer je ta niz uporabljen. Druga vrsta nizov, nizi z oblikami množine, vključuje dve okenci za prikaz dveh izvornih nizov in zavihkov, tako da lahko nastavite različne končne oblike. Po drugi strani, nizi plural form vključujejo dva prostora za prikaz dveh izvornih nizov in zavihke, da lahko tako nastavite različne končne oblike.

Vsakič, ko spremenite vaše vire in morate posodobiti prevode, samo kliknite Refresh in Poedit bo znova preveril kodo, odstranil neobstoječe vnose, združil tiste, ki so se spremenili, in dodal nove. Prav tako lahko poskusi uganiti nekaj prevodov, ki temeljijo na drugih, ki ste jih vnesli. Ta ugibanja in spremenjeni vnosi bodo prejeli oznako »Fuzzy«, ki označuje, da jih je potrebno pregledati, pri čemer so poudarjeni v seznamu. Prav tako je uporabno, če imate prevajalsko ekipo in nekdo skuša napisati nekaj za kar ni prepričan: Samo označite Fuzzy in nekdo drug bo to pregledal kasneje.

Priporočljivo je pustiti »View > Untranslated entries first« označen, saj vam bo zelo pomagalo, da ne pozabite kakšnega vpisa. Iz tega menija lahko tudi odprete dele uporabniškega vmesnika, ki vam omogočajo pustiti vsebinske informacije za prevajalce, če je potrebno.

Nasveti in triki

Možne težave pri predpomnjenju

Če poganjate PHP kot modul za Apache (mod_php), se boste morda soočili s težavami predpomnjenja datotek .mo. To se zgodi prvič, ko se preberejo, ter, ko jih osvežite, boste morda morali znova zagnati strežnik. Na nginx in PHP5 ponavadi traja le nekaj osvežitev strani za osvežitev predpomnilnika prevodov. Na PHP7 je to redko potrebno.

Dodatne pomožne funkcije

Veliko ljudi ima raje lažjo uporabo _ () namesto gettext(). Veliko knjižnic i18n po meri iz ogrodij uporabljajo tudi nekaj podobnega t(), da je koda prevoda krajša. Kljub temu pa je to edina funkcija za bližnjico. Morda boste želeli dodati v vaš projekt še nekatere druge, kot so __() ali _n() za ngettext(), ali morda lično _r(), kar združi klica gettext() in sprintf(). Druge knjižnice, kot je php-gettext’s Gettext ponujajo tudi pomožne funkcije, kot so te.

V teh primerih boste morali navesti pripomočku Gettext, kako izvleči nize iz teh novih funkcij. Ne bojte se, to je zelo enostavno. To je samo polje v datoteki .po, ali nastavitev zaslona na Poedit. V urejevalniku je ta možnost znotraj »Catalog > Properties > Source keywords«. Vključiti pa morate specifikacije tistih novih funkcij, ki sledijo določeni obliki:

Po vključitvi teh novih pravil v datoteko .po se bo pričelo novo skeniranje v vaših nizih, prav tako enostavno kot prej.

Viri

Nazaj na vrh

Injiciranje odvisnosti

Iz Wikipedije:

Injiciranje odvisnosti je programski načrtovalski vzorec, ki omogoča odstranitev zacementiranih odvisnosti in omogoča njihovo spreminjanje, kadarkoli v času zagona ali prevajanja programa.

Ta citat naredi koncept veliko bolj zapleten, kot dejansko je. Injiciranje odvisnosti ponuja komponento z njenimi odvisnostmi ali skozi konstruktorjevo injiciranje, klic metode, ali nastavitvijo lastnosti. Tako enostavno je.

Osnovni koncept

Koncept lahko demonstriramo z enostavnim in naivnim primerom.

Imamo razred Database, ki zahteva, da adapter komunicira s podatkovno bazo. Instanco adapterja naredimo v konstruktorju in izdelamo direktno odvisnost. To oteži testiranje in pomeni, da je razred Database zelo tesno povezan v adapter.

<?php
namespace Database;

class Database
{
    protected $adapter;

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

class MysqlAdapter {}

To kodo je mogoče preurediti, da uporablja injiciranje odvisnosti in zato naredi odvisnost ohlapnejšo. Tu injiciramo odvisnost v konstruktor in uporabimo napredovanje lastnosti konstruktorja, da je na voljo kot lastnost po razredu:

<?php
namespace Database;

class Database
{
    public function __construct(protected MySqlAdapter $adapter)
    {
    }
}

class MysqlAdapter {}

Sedaj dajemo razredu Database njegovo odvisnost namesto, da jo ustvari sam. Lahko naredimo celo metodo, ki bi sprejela argument odvisnosti in ga nastavila na ta način, ali pa če bi bila lastnost $adapter nastavljena kot public, bi jo lahko nastavili direktno.

Kompleksni problem

Če ste kdarkoli brali o injiciranju odvisnosti, potem ste verjeno videli izraz »inverzija nadzora« (angl. inversion of control) ali »princip inverzije odvisnosti« (angl. dependency inversion principle). To so kompleksni problemi, ki jih injiciranje odvisnosti rešuje.

Inverzija nadzora

Inverzija nadzora je, kot pove izraz, »obračanje nadzora« sistema z obdržanjem organizacijske kontrole v celoti ločene od naših objektov. V terminih injiciranja odvisnosti to pomeni rahljanje naših odvisnosti s kontroliranjem in njihovo instantizacijo drugje v sistemu.

Že leta so ogrodja PHP dosegala inverzijo nadzora, vendar vprašanje je postalo, kateri del nadzora obračate in kam? Na primer, MVC ogrodja bi običajno podala super objekt ali osnovni krmilnik, ki ga morajo ostali krmilniki razširiti, da pridobijo dostop do svojih odvisnosti. To je inverzija nadzora, čeprav namesto rahljanja odvisnosti, jih ta metoda enostavno premakne.

Injiciranje odvisnosti nam omogoča bolj elegantno rešiti ta problem z injiciranjem samo tistih odvisnosti, ki jih potrebujemo, ko jih potrebujemo, brez potrebe za kakršnekoli vkodirane odvisnosti.

S.O.L.I.D.

Načelo enotne odgovornosti

Načelo enotne odgovornosti (angl. single responsibility principle) se nanaša na akterje v visoko nivojski arhitekturi. Trdi, da mora imeti razred A samo en razlog za spremembo. To pomeni, da mora imeti vsak razred odgovornost samo nad enim delom funkcionalnosti ponujene s programom. Največja prednost tega pristopa je, da omogoči izboljšavo ponovne uporabe kode. Z načrtovanjem naših razredov, da naredijo samo eno opravilo, jih lahko uporabimo (ali ponovno uporabimo) v katerem koli drugem programu brez spremembe.

Načelo odprt/zaprt

Načelo odprt/zaprt (angl. open/closed principle) se nanaša na načrt razreda in lastnosti razširitve. Trdi, da morajo biti programske entitete (razredi, moduli, funkcije itd.) odprti za razširitev, vendar zaprti za spremembe. To pomeni, da moramo načrtovati naše module, razrede in funkcije tako, da ko je potrebna nova funkcionalnost, ne potrebujemo spremeniti naše obstoječe kode, vendar napišemo raje novo kodo, ki bo uporabljala že obstoječo kodo. Praktično to pomeni, da moramo pisati razrede, ki izvajajo in se držijo vmesnikov in nato namignemo tip teh vmesnikov namesto točno določenih razredov.

Največja prednost tega pristopa je, da lahko zelo enostavno razširimo našo kodo s podporo za nekaj novega brez potrebe po spremembi obstoječe kode, kar pomeni, da lahko zreduciramo čas QA in tveganje za negativen vpliv na aplikacijo je bistveno zmanjšan. Novo kodo lahko naložimo hitreje in z večjo samozavestjo.

Načelo substitucije Liskov

Načelo substitucije Liskov (angl. Liskov substitution principle) se nanaša na podtipe in dedovanje. Trdi, da podrejeni razredi ne bi smeli vplivati na definicije nadrejenih razredov. Ali z besedami Robert C. Martina, podtipi morajo biti zamenljivi za njihove osnovne tipe.

Na primer, če imamo vmesnik FileInterface, ki definira metodo embed() in imamo razreda Audio in Video, ki oba implementirata vmesnik FileInterface, potem lahko pričakujemo, da bo uporaba metode embed() vedno naredila to, kar nameravamo. Če kasneje ustvarimo razred PDF ali Gist, ki implementira vmesnik FileInterface, bomo vedeli in razumeli, kaj bo metoda embed naredila. Največja prednost tega pristopa je, da imamo zmožnost zgraditi fleksibilne in enostavno nastavljive programe, ker lahko spremenimo en objekt določenega tipa (npr. FileInterface) v drugega, brez da bi spremenili karkoli drugega v programu.

Načelo ločevanja vmesnikov

Načelo ločevanja vmesnkov (angl. interface segregation principle - ISP) se nanaša na komunikacijo poslovne logike klientov. Trdi, da noben klient ne bi smel biti prisiljen v odvisnost metod, ki jih ne uporablja. To pomeni, da namesto, da imamo posamezen monoliten vmesnik, ki ga morajo implementirati vsi skladni razredi, moramo namesto tega ponuditi nabor manjših, konceptualno specifičnih vmesnikov, ki le tega ali več njih skladajoči razred implementira.

Na primer, razreda Car ali Bus bi morda potrebovala metodo steeringWheel(), vendar razreda Motorcycle ali Tricycle ne bi. Nasprotno, razreda Motorcycle ali Tricycle, bi potrebovala metodo handlebars(), vendar Car ali Bus pa ne. Ni potrebe, da imajo vsi te tipi vozil podporo tako za steeringWheel() kot tudi za handlebars(). Torej izvorna razreda razdelimo narazen.

Princip inverzije odvisnosti

Princip inverzije odvisnosti (angl. dependency injection principle) je »D« v skupku objekta orientiranih načrtovalskih principov S.O.L.I.D., ki pravijo, da bi moralo biti »Odvisno od abstrakcije. Ne zanašamo se na konkretizacijo.« Enostavneje povedano, to pomeni, da bi morale biti naše odvisnosti vmesniki/vezave ali abstraktni razredi namesto konkretne implementacije. Zgornji primer lahko enostavno refkatoriramo, da sledi temu principu.

<?php
namespace Database;

class Database
{
    public function __construct(protected AdapterInterface $adapter)
    {
    }
}

interface AdapterInterface {}

class MysqlAdapter implements AdapterInterface {}

Na voljo je nekaj koristi od razreda Database, ki je sedaj odvisen od vmesnika namesto od konkretizacije.

Zamislite si, da delamo v ekipi in na adapterju dela kolega. V našem prvem primeru, bi morali čakati omenjenega kolega, da konča adapter preden ga lahko ustrezno preizkusimo za naše teste enot. Sedaj, ko je odvisnost vmesnik/vezava lahko veselo preizkusimo ta vmesnik in vemo, da bo naš kolega zgradil adapter na osnovi te vezave.

Še večja korist te metode je, da je sedaj naša koda bolj razširljiva. Če se leto dni kasneje odločimo, da se želimo preseliti na drug tip podatkovne baze, lahko napišemo adapter, ki implementira originalni vmesnik in namesto tega to injicira, nič več preurejanja (angl. refactoring) ne bi bilo potrebnega, saj lahko zagotovimo, da adapter sledi vezavi nastavljeni s strani vmesnika.

Kontejnerji

Prva stvar, ki bi jo morali razumeti o kontejnerjih injiciranja odvisnosti je, da niso enaka stvar kot injiciranje odvisnosti. Kontejner je pomožna prikladnost, ki nam pomaga implementirati injiciranje odvisnosti, vendar so lahko pogostokrat napačno uporabljeni, da implementirajo proti-vzorec, storitveni lokator. Injiciranje kontejnerja DI (dependency injection) kot storitvenega lokatorja v naših razredih verjetno naredi težje odvisnosti na kontejnerju kot odvisnost, ki jo zamenjujete. Tudi kodo naredi veliko bolj transparentno in konec koncev težjo za testiranje.

Veliko modernih ogrodij ima svoje lastne kontejnerje injiciranja odvisnosti, ki vam omogočajo povezati odvisnosti skupaj skozi nastavitve. Kaj to pomeni v praksi, je, da lahko pišete kodo aplikacije, ki je čista in ločena, kot ogrodje na katerem je zgrajena.

Nadaljnje branje

Nazaj na vrh

Podatkovne baze

Mnogokrat bo vaša koda PHP koda uporabila podatkovno bazo za pridobivanje informacij. Na voljo imate nekaj možnosti za povezavo in interakcijo z vašo podatkovno bazo. Priporočena možnost do PHP 5.1.0 je bila uporaba originalnih gonilnikov, kot so mysqli, pgsql, mssql itd.

Originalni gonilniki so odlični, če uporabljate v vaši aplikaciji samo eno podatkovno bazo, vendar če, na primer, uporabljate MySQL in nekaj MSSQL hkrati, ali pa se morate povezati na podatkovno bazo Oracle, potem ne boste mogli uporabiti istih gonilnikov. Naučiti se boste morali popolnoma nov API za vsako podatkovno bazo – in to lahko postane trapasto.

Razširitev MySQL

Razširitev mysql za PHP je izjemno stara in je bila nadomeščena z dvema drugima razširitvima:

Ne samo, da se je razvoj na mysql ustavil dolgo nazaj, razširitev je bila uradno odstranjena v PHP 7.0.

Da si prihranite čas s poglabljanjem v vaše nastavitve php.ini, da ugotovite, katere module uporabljate, obstaja tudi možnost, da poiščete mysql_* v vašem priljubljenem urejevalniku. Če se pojavi katerakoli izmed funkcij, kot je mysql_connect, ali mysql_query, potem je v uporabi mysql.

Tudi če še ne uporabljate PHP 7.x ali novejšega, bo izpustitev nadgradnje, kakor hitro je mogoče, vodila k še večjim težavam, ko boste prišli do nadgradnje PHP. Najboljša možnost je zamenjati uporabo mysql z mysqli ali PDO v vaših aplikacijah znotraj vašega razvojnega razporeda, tako da se vam ne bo kasneje mudilo.

Če nadgrajujete iz mysql na mysqli, bodite pozorni o lenobnih vodičih nadgradnje, ki enostavno predlagajo najti in zamenjati mysql_* z mysqli_*. Ne samo, da je to prevelika posplošitev, pozablja tudi prednosti, ki jih mysqli ponuja, kot je vezava parametrov, ki je ponujena tudi v PDO.

Razširitev PDO

PDO je abstraktna knjižnica povezovanja podatkovne baze – vgrajen v PHP od 5.1.0 – ki ponuja enoten vmesnik za komunikacijo z mnogimi različnimi podatkovnimi bazami. Na primer uporabite lahko v osnovi identično kodo za vmesnik z MySQL ali SQLite:

<?php
// PDO + MySQL
$pdo = new PDO('mysql:host=example.com;dbname=database', 'user', 'password');
$statement = $pdo->query("SELECT some_field FROM some_table");
$row = $statement->fetch(PDO::FETCH_ASSOC);
echo htmlentities($row['some_field']);

// PDO + SQLite
$pdo = new PDO('sqlite:/path/db/foo.sqlite');
$statement = $pdo->query("SELECT some_field FROM some_table");
$row = $statement->fetch(PDO::FETCH_ASSOC);
echo htmlentities($row['some_field']);

PDO ne bo prevajal vaših poizvedb SQL ali emuliral manjkajočih lastnosti. Namenjen je izključno povezovanju večih tipov podatkovnih baz z istim API-jem.

Bolj pomembno, PDO vam dovoljuje varno vstavljanje tujih vhodov (npr. ID-jev) v vaše poizvedbe SQL brez skrbi pred podatkovno baznimi vstavljenimi napadi SQL. To je mogoče z uporabo stavkov PDO in vezanih parametrov.

Predpostavimo, da skript PHP dobi numeričen ID za parameter poizvedbe. Ta ID bi moral biti uporabljen za pridobitev zapisa iz baze. To je napačen način:

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

To je grozna koda. Vstavljate izvorni parameter poizvedbe v SQL poizvedbo. Tako dopustite možen izjemno hiter napad z uporabo prakse imenovane [injiciranje SQL]. Samo predstavljajte si, da bi napadalec poslal sledeči iznajdljivi parameter id s klicem preko URL-ja, kot je http://domain.com/?id=1%3BDELETE+FROM+users. To bi nastavilo spremenljivko $_GET['id'] na 1;DELETE FROM users, kar bi izbrisalo vse vaše uporabnike! Namesto tega bi morali očistiti vnos ID z uporabo veznih parametrov PDO.

<?php
$pdo = new PDO('sqlite:/path/db/users.db');
$stmt = $pdo->prepare('SELECT name FROM users WHERE id = :id');
$id = filter_input(INPUT_GET, 'id', FILTER_SANITIZE_NUMBER_INT); // <-- filter your data first (see [Data Filtering](#data_filtering)), especially important for INSERT, UPDATE, etc.
$stmt->bindParam(':id', $id, PDO::PARAM_INT); // <-- Automatically sanitized for SQL by PDO
$stmt->execute();

To je pravilna koda. Uporablja vezni parameter na stavku PDO. To počisti tuj vnosni ID preden se ga predstavi podatkovni bazi, kar preprečuje potencialne vstavljene napade SQL.

Za pisanja, kot sta INSERT ali UPDATE, je posebno pomembno, da še vedno najprej filtrirate vaše podatke in jih počistite za drugimi stvarmi (odstranitev značk HTML, JavaScript-a itd.). PDO ga bo samo počistil za SQL, vendar ne pa za vašo aplikacijo.

Morate se tudi zavedati, da povezave podatkovne baze uporabljajo vire in pogostokrat se je že zgodilo, da so bili vsi viri zasedeni, če povezave niso bile implicitno zaprte, čeprav je to bolj običajno v drugih jezikih. Z uporabo PDO, lahko implicitno zaprete vaše povezave z uničenjem objekta in zagotovite, da so vse preostale reference nanj izbrisane, t. j. nastavljene na NULL. Če ne naredite tega eksplicitno, bo PHP avtomatsko zaprl povezavo, ko se skript konča - razen seveda, če uporabljate trajne povezave.

Interakcija s podatkovnimi bazami

Ko se razvijalci prvič pričnejo učiti PHP, pogosto končajo z mešanjem njihovih interakcij s podatkovnimi bazami z njihovo predstavitveno logiko in uporabijo kodo, ki izgleda nekako tako:

<ul>
<?php
foreach ($db->query('SELECT * FROM table') as $row) {
    echo "<li>".$row['field1']." - ".$row['field1']."</li>";
}
?>
</ul>

To je slaba praksa zaradi vseh vrst razlogov, v glavnem ker je težko razhroščevati, težko testirati, težko brati in izpisalo bo veliko polj, če tam ne postavite omejitve.

Medtem ko obstoja veliko ostalih rešitev za to - odvisno od tega, če imate raje OOP ali funkcijsko programiranje - mora biti nek element ločitve.

Premislite o najbolj osnovnem koraku:

<?php
function getAllFoos($db) {
    return $db->query('SELECT * FROM table');
}

$results = getAllFoos($db);
foreach ($results as $row) {
    echo "<li>".$row['field1']." - ".$row['field1']."</li>"; // BAD!!
}

To je dober začetek. Dajte ta dva elementa v dve različni datoteki in imate nekoliko čisto ločitev.

Izdelajte razred, kamor date to metodo in imate »Model«. Izdelajte enostavno datoteko .php, kamor date predstavitveno logiko in imate »View«, kar je zelo blizu MVC - skupni arhitekturi OOP za večino ogrodij.

foo.php

<?php
$db = new PDO('mysql:host=localhost;dbname=testdb;charset=utf8mb4', 'username', 'password');

// Make your model available
include 'models/FooModel.php';

// Create an instance
$fooModel = new FooModel($db);
// Get the list of Foos
$fooList = $fooModel->getAllFoos();

// Show the view
include 'views/foo-list.php';

models/FooModel.php

<?php
class FooModel
{
    public function __construct(protected PDO $db)
    {
    }

    public function getAllFoos() {
        return $this->db->query('SELECT * FROM table');
    }
}

views/foo-list.php

<?php foreach ($fooList as $row): ?>
    <li><?= $row['field1'] ?> - <?= $row['field1'] ?></li>
<?php endforeach ?>

To je v bistvu enako, kar počne večina modernih ogrodij, čeprav nekoliko bolj ročno. Lahko ne boste potrebovali narediti vsega tega vsakokrat, vendar mešanje skupaj preveč predstavitvene logike in interakcij s podatkovno bazo je lahko pravi problem, če kadarkoli želite narediti teste enot za vašo aplikacijo.

Plasti abstrakcije

Mnoga ogrodja ponujajo njihovo lastno plast abstrakcije, ki lahko ali pa ne sedi na vrhu PDO. Te bodo pogosto posnemale lastnosti za sistem ene podatkovne baze, ki manjka pri drugi z ovitjem poizvedb v metode PHP, kar vam da dejansko abstrakcijo podatkovne baze namesto samo abstrakcije povezave, ki jo PDO ponuja.

To bo seveda dodalo nekaj prekomernosti, vendar če gradite prenosno aplikacijo, ki mora delovati z MySQL, PostgreSQL in SQLite, potem bo to vredno zaradi čistosti kode.

Nekatere plasti abstrakcije so bile zgrajene z uporabo standardov imenskih prostorov PSR-0 ali PSR-4, tako da se jih lahko namesti v katerokoli aplikacijo želite:

Nazaj na vrh

Predloge

Predloge ponujajo priročen način ločitve logike vašega krmilnika in domene iz vaše logike prezentacije. Predloge običajno vsebujejo HTML vaše aplikacije, vendar so lahko uporabljene tudi za ostale oblike, kot je XML. Na predloge se pogosto sklicuje kot »pogledi« (angl. views), ki naredijo del druge komponente model–view–controller (MVC) vzorca arhitekture programske opreme.

Koristi

Glavna korist uporabe predlog je jasna ločitev, ki jo naredijo med logiko predstavitve in ostalo vašo aplikacijo. Predloge imajo izključno odgovornost prikaza vsebine oblike. Niso odgovorne za iskanje podatkov, pridobivanje in ostala bolj kompleksna opravila. To vodi v čistejšo in bolj bralno kodo, ki je posebej priročna v okolju ekip, kjer razvijalci delajo na kodi strežniške strani (krmilniki, modeli) in oblikovalci delajo na kodi strani odjemalca (oblikovanje).

Predloge tudi izboljšajo organizacijo kode predstavitve. Predloge so običajno postavljene v mapi »views«, vsaka pa je definirana znotraj ene datoteke. Ta pristop spodbuja ponovno uporabo kode, kjer so večji bloki kode razbiti v manjše ponovno uporabne dele, pogosto imenovani deli (angl. partials). Na primer, glava in noga vaše strani sta lahko definirani vsaka kot predloga, ki je nato vključena pred in za vsako predlogo strani.

Končno, odvisno od knjižnice, ki jo uporabljate, predloge lahko ponujajo več varnosti z avtomatičnim čiščenjem uporabniško generirane vsebine. Nekatere knjižnice celo ponujajo peskovnik, kjer oblikovalci predlog dobijo samo dostop do dovoljenega seznama spremenljivk in funkcij.

Osnovne predloge PHP

Osnovne predloge PHP so enostavno predloge, ki uporabljajo prvotno kodo PHP. So naravna izbira, ker je PHP dejansko jezik predlog sam po sebi. To enostavno pomeni, da lahko kombinirate kodo PHP znotraj druge kode, kot je HTML. To je koristno za razvijalce PHP, saj se ni za naučiti nobene nove sintakse, poznajo funkcije, ki so jim na voljo in njihovi urejevalniki kode že imajo vgrajeno označevanje sintakse PHP in avtomatsko zaključevanje. Dalje, osnovne predloge PHP se nagibajo k temu, da so kakor se le da hitre, saj ni potrebne nobene faze prevajanja kode.

Vsako moderno ogrodje PHP vključuje neko vrsto sistema predlog, večina od teh uporablja privzeto osnovni PHP. Zunaj ogrodij, knjižnice kot je Plates, ali Aura.View delujejo z osnovnimi predlogami PHP enostavnejše s ponujanjem moderne funkcionalnosti predlog, kot je dedovanje, postavitve in razširitve.

Enostaven primer osnovne predloge PHP

Uporaba knjižnice Plates:

<?php // user_profile.php ?>

<?php $this->insert('header', ['title' => 'User Profile']) ?>

<h1>User Profile</h1>
<p>Hello, <?=$this->escape($name)?></p>

<?php $this->insert('footer'i) ?>

Primer osnovne predloge PHP z uporabo dedovanja

Uporaba knjižnice Plates.

<?php // template.php ?>

<html>
<head>
    <title><?=$title?></title>
</head>
<body>

<main>
    <?=$this->section('content')?>
</main>

</body>
</html>
<?php // user_profile.php ?>

<?php $this->layout('template', ['title' => 'User Profile']) ?>

<h1>User Profile</h1>
<p>Hello, <?=$this->escape($name)?></p>

Prevedene predloge

Medtem ko se je PHP razvil v zrel, objektno orientiran jezik, se ni veliko izboljšal kot jezik predlog. Prevedene predloge, kot so Twig, Brainy, ali Smarty*, zapolnjujejo to praznino s ponujanjem nove sintakse, ki je bila sestavljena posebej za predloge. Od avtomatskega čiščenja, do dedovanja in poenostavljenih krmilnih struktur, so prevedene predloge načrtovane za enostavnejše pisanje, čistejše branje in varnejše za uporabo. Prevedene predloge so lahko celo deljene med različnimi jeziki, Mustache je dober primer tega. Ker morajo biti te predloge prevedene, prihaja do manjšega udarca na zmogljivost, vendar je ta zelo minimalen, ko je uporabljeno ustrezno predpomnjenje.

*Medtem ko Smarty ponuja avtomatsko čiščenje, ta lastnosti NI omogočena privzeto.

Enostaven primer prevedene predloge

Uporaba knjižnice Twig.

{% include 'header.html' with {'title': 'User Profile'} %}

<h1>User Profile</h1>
<p>Hello, {{ name }}</p>

{% include 'footer.html' %}

Primer prevedenih predlog z uporabo dedovanja

Uporaba knjižnice Twig.

// template.html

<html>
<head>
    <title>{% block title %}{% endblock %}</title>
</head>
<body>

<main>
    {% block content %}{% endblock %}
</main>

</body>
</html>
// user_profile.html

{% extends "template.html" %}

{% block title %}User Profile{% endblock %}
{% block content %}
    <h1>User Profile</h1>
    <p>Hello, {{ name }}</p>
{% endblock %}

Nadaljnje branje

Članki in vodniki

Knjižnice

Nazaj na vrh

Napake in izjeme

Napake

Kadarkoli gre kaj narobe, bo v mnogih programskih jezikih »polnih izjem« vržena izjema. To je zagotovo izvedljiv način za urejanje stvari, vendar PHP je jezik, ki ni poln izjem. Medtem ko ima izjeme in vedno več jedra jih pričenja uporabljati, ko se dela za objekti, bo večina samega PHP-ja poskušala nadaljevati s pocesiranjem ne glede na to, kaj se zgodi, razen v primeru usodnih napak.

Na primer:

$ php -a
php > echo $foo;
Notice: Undefined variable: foo in php shell code on line 1

To je samo napaka z obvestilom in PHP se bo veselo poganjal naprej. To je lahko zmedeno za tiste, ki prihajajo iz jezikov polnih izjem, ker sklicevanje na manjkajoče spremenljivke, na primer v Pythonu, bo vrglo izjemo:

$ python
>>> print foo
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'foo' is not defined

Edina prava razlika je, da bo Python ponorel ob vsaki manjši stvari, da so lahko razvijalci prepričani, da bo ujeta katerakoli potencialna težava ali redek primer, kjer pa PHP nadaljuje s procesiranjem razen, če se zgodi kaj ekstremnega, kjer vrže napako in o njej poroča.

Resnost napake

PHP ima nekaj nivojev resnosti napak. Tri najbolj pogosti tipi sporočil so napake, obvestila in opozorila. Ta imajo različne nivoje resnosti; E_ERROR, E_NOTICE in E_WARNING. Napake so usodne napake pri poganjanju in so običajno povzročene zaradi napak v vaši kodi ter jih je potrebno popraviti, saj bodo povzročile, da se PHP ne bo več poganjal. Obvestila so svetovalna sporočila povzročena s strani kode, ki lahko ali pa ne povzročajo probleme med izvajanjem skripta in izvajanje ni ustavljeno. Opozorila so ne-usodne napake, izvajanje skripta ne bo ustavljeno.

Drug tip sporočil napak poročan med časom priprave je sporočilo E_STRICT. Ta sporočila so uporabljena za predlog sprememb vaše kode, da pomagajo zagotoviti najboljšo interoperabilnost in nadaljnjo združljivost s prihajajočimi različicami PHP-ja.

Sprememba obnašanja poročanja napak PHP

Poročanje napak je možno spremeniti z uporabo nastavitev PHP in/ali klicev funkcij PHP. Z uporabo vgrajene funkcije PHP error_reporting() lahko nastavite nivo napak za trajanje izvajanja skripta s podajanjem ene izmed vnaprej definirane konstante nivoja napak, kar pomeni, če želite videti samo napake in opozorila - vendar ne obvestil - potem lahko nastavite to:

<?php
error_reporting(E_ERROR | E_WARNING);

Lahko tudi krmilite ali so napake prikazane ali ne na zaslonu (dobro za razvoj) ali v skriptu in beležene (dobro za produkcijo). Za več informacij na to temo preverite sekcijo Poročanje napak.

Medvrstično zatiranje napak

PHP-ju lahko tudi poveste, da zatre določene napake z operatorjem kontrole napak @. Ta operator dodate na začetek izraza in katerakoli napaka, ki je direktni rezultat izraza, je utišana.

<?php
echo @$foo['bar'];

To bo izpisalo $foo['bar'], če obstaja, vendar bo enostavno vrnilo null in nič izpisalo, če spremenljivka $foo ali ključ 'bar' ne obstaja. Brez operatorja kontrole napak lahko ta izraz ustvari napako PHP Notice: Undefined variable: foo ali PHP Notice: Undefined index: bar.

To lahko zgleda kot dobra ideja, vendar pride do nekaterih nezaželjenih kompromisov. PHP upravlja izraze, ki uporabljajo @ v manj zmogljivem načinu kot tiste brez @. Prezgodnja optimizacija je lahko izhodišče vseh programerskih prepirov, vendar če je zmogljivost posebej pomembna za vašo aplikacijo/knjižnico, je pomembno razumeti posledice zmogljivosti operatorja kontrole napak.

V nadaljevanju operator kontrole napak popolnoma pogoltne napako. Napaka ni izpisana in napaka ni poslana v dnevnik napak. Tudi celotni/produkcijski sistemi PHP nimajo načina izključitve operatorja napak. Medtem ko imate lahko prav, da je napaka, ki jo vidite, neškodljiva, bo druga manj škodljiva napaka tudi utišana.

Če obstaja način, kako se izogniti operatorju zatiranja napak, premislite o njem. Na primer našo kodo zgoraj se lahko prepiše takole:

<?php
// Null Coalescing Operator.
echo $foo['bar'] ?? '';

Primer, kjer je zatiranje napak lahko smiselno, je, kjer fopen() ne uspe najti datoteke za nalaganje. Lahko preverite obstoj datoteke, preden jo poskušate naložiti, vendar če je datoteka izbrisana po preverjanju in pred fopen() (kar zveni nemogoče, vendar se lahko zgodi) potem bo fopen() vrnil false in vrgel napako. To je potencialno nekaj, kar bi moral PHP razrešiti, vendar gre za en primer, kjer je zatiranje napak edina veljavna rešitev.

Prej smo omenili, da ni načina v celotnem sistemu PHP, da se izključi operator kontrole napak. Vendar xDebug ima nastavitev ini xdebug.scream, ki onemogoči operator kontrole napak. To lahko nastavite preko vaše datoteke php.ini takole:

xdebug.scream = On

To vrednost lahko tudi nastavite na začetku poganjanja s funkcijo ìni_set:

<?php
ini_set('xdebug.scream', '1')

To je najbolj uporabno, ko razhroščujete kodo in sumite, da bo informativna napaka zatrta. Uporabite scream previdno in kot začasno razhroščevalno orodje. Na voljo je ogromno knjižnične kode PHP, ki lahko ne bo delala z onemogočenim operatorjem kontrole napak.

ErrorException

PHP je odlično sposoben biti programski jezik »poln izjem« in zahteva samo nekaj vrstic kode za pretvorbo. V osnovi lahko vržete vaše »napake« kot »izjeme« z uporabo razreda ErrorException, ki razširi razred Exception.

To je pogosta praksa implementirana s strani velikega števila modernih ogrodij, ko sta Symfony in Laravel. V načinu razhroščevanja (ali razvojnem okolju dev) bosta obe ogrodji prikazali lepo in jasno sled sklada.

Na voljo so tudi nekateri paketi za boljšo upravljanje z napakami in izjemami, kot je Whoops!, ki je privzeto nameščen v Laravel in se ga lahko uporablja tudi v kateremkoli drugem ogrodju.

Z vrženjem napak kot izjem jih v razvoju lahko upravljate bolje kot običajne rezultate in če vidite izjemo med razvojem, jo lahko ovijete v stavek catch z določenimi navodili, kako upravljati v tej situaciji. Vsaka izjema, ki jo ujamete, bo takoj naredila vašo aplikacijo malenkost bolj robustno.

Več infomacij na to temo in podrobnosti kako uporabljati ErrorException pri upravljanju napak, se lahko najde na ErrorException Class.

Izjeme

Izjeme (angl. exceptions) so standardni deli najbolj popularnih programskih jezikov, vendar so pogosto spregledani s strani programerjev PHP. Jeziki, kot je Ruby, so izjemno zapolnjeni z izjemami, tako da kadarkoli gre kaj narobe, kot npr. okvara zahtevka HTTP, ali okvara pri poizvedbi podatkovne baze, ali celo ko slikovnega stredstva ni mogoče najti, bodo Ruby (ali uporabljeni gemi) izpisali izjemo na zaslon, kar pomeni, da takoj veste, kje se nahaja napaka.

PHP sam po sebi ima precej pomankljivosti glede tega in klic file_get_contents() vam bo ponavadi vrnil FALSE in opozorilo. Mnoga starejša ogrodja, kot je na primer CodeIgniter, bodo vrnila samo vrednost false, zapis sporočila v dnevnik in mogoče vam omogočila uporabo metode, kot je $this->upload->get_error(), da lahko vidite, kaj je šlo narobe. Problem tu je, da morate iskati napako in preverjati dokumentacijo, za katero napako metode gre pri določenem razredu, namesto da se to naredi izjemno očitno.

Naslednji problem je, ko razredi avtomatsko vržejo napako na zaslon in zapustijo proces. Ko naredite to, ustavite drugega razvijalca, da bi lahko dinamično ravnal s to napako. Izjeme bi morale biti zagnane, da opozorijo razvijalca pred napako. Nato le-ta lahko izbere, kako bo ravnal v tem primeru. Primer:

<?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)
{
    // The validation failed
}
catch(Fuel\Email\SendingFailedException $e)
{
    // The driver could not send the email
}
finally
{
    // Use this to let user know email was sent
}

Izjeme SPL

Generični razred Exception ponuja zelo malo konteksta razhroščevanja za razvijalca, čeprav za odpravo tega je mogoče narediti specializiran tip Exception s pomočjo podrazreda generičnega razreda Exception:

<?php
class ValidationException extends Exception {}

To pomeni, da lahko dodate več blokov catch in upravljate z različnimi izjemami na različne načine. To lahko vodi v ustvarjanje veliko izjem po meri, nekaterim med njimi se lahko izognete z uporabo izjem SPL, ki so na voljo v razširitvi SPL.

Če na primer uporabite magično metodo __call() in je nato zahtevana napačna metoda, se namesto zagona standardne izjeme Exception, ki je nejasna, ali ustvarjanja izjeme po meri samo za to, lahko zažene throw new BadMethodCallException;.

Nazaj na vrh

Varnost

Najboljši najdeni vir o varnosti PHP je Vodnik 2018 za gradnjo varne programske opreme PHP avtorjev Paragon Initiative.

Varnost spletnih aplikacij

Za vsakega razvijalca PHP je pomembno, da se nauči osnov varnosti spletnih aplikacij, ki se lahko razčlenijo na peščico širokih tem:

  1. Ločevanje kode in podatkov.
    • Ko se podatki izvršujejo kot koda, dobite vrivanje SQL, napad XSS, vključevanje lokalnih/oddaljenih datotek itd.
    • Ko je koda izpisana kot podatek, dobite uhajanje informacij, (razkritje izvorne kode, ali v primeru programov C, dovolj informacij za zaobiti ASLR).
  2. Logika aplikacije.
    • Manjkajoče overjanje ali kontrola avtorizacije.
    • Preverjanje vnosa.
  3. Operativno okolje.
    • Različice PHP.
    • Tretje osebne knjižnice.
    • Operacijski sistem.
  4. Slabosti kriptografije.

Obstajajo slabi ljudje pripravljeni in voljni izkoristiti vašo spletno aplikacijo. Pomembno je, da naredite ustrezne varnostne ukrepe za izboljšanje varnosti vaše spletne aplikacije. Na srečo so dobri ljudje pri The Open Web Application Security Project (OWASP) prevedli zgoščen seznam znanih varnostnih težav in metod, da se lahko zaščitite pred napadalci. To je obvezno branje za varnostno ozaveščenega razvijalca. Drug dober vodič za varnost spletnih aplikacij PHP je tudi Survive The Deep End: PHP Security avtorja Padraic Brady.

Zgoščevanje gesel

Eventuelno vsakdo zgradi aplikacijo PHP, ki uporablja uporabniško prijavo. Uporabniška imena in gesla so lahko shranjena v podatkovni bazi in potem uporabljena za potrjevanje uporabnikov pri prijavi.

Pomembno je, da se gesla ustrezno zgosti, preden se jih shrani. Zgoščevanje in šifriranje sta dve zelo različni stvari, ki sta pogosto razlog za zmedo.

Zgoščevanje je nepovratna, enosmerna funkcija izvedena nad uporabnikovim geslom. To naredi končno določen dolg niz, ki se ga ne da enostavno povrniti. To pomeni, da lahko primerjate zgostitev z drugo, da ugotovite, če obe prihajata iz istega vira niza, vendar pa ne morete določiti osnovnega niza. Če gesla niso zgoščena in je vaša podatkovna baza dostopna s strani neavtorizirane tretje strani, so vsi uporabniški računi ogroženi.

Z razliko od zgoščevanja, je šifriranje povratno (pod pogojem, da imate ključ). Šifriranje je uporabno na drugih področjih, vendar je slaba strategija za varno shranjevanje gesel.

Gesla bi morala biti posamezno soljena z dodajanjem naključnega niza za vsako geslo pred zgoščevanjem. To preprečuje napade s slovarji in z uporabo »mavričnih tabel« (obratni seznam kriptografskih zgostitev za pogosta gesla).

Zgoščevanje in soljenje sta izjemnega pomena, saj uporabniki pogostokrat uporabljajo enako geslo za več storitev in kvaliteta gesla je lahko slaba.

Dodatno bi morali uporabljati poseben algoritem zgoščevanja gesel, namesto hitre, splošno uporabljene kriptografske funkcije zgoščevanja (npr. SHA256). Kratek seznam sprejemljivih algoritmov za zgoščevanje gesel za uporabo (od junija 2018) so:

Na srečo, dandanes PHP to naredi enostavno.

Zgoščevanje gesel s password_hash

V PHP 5.5 je bila izdana funkcija password_hash(). Trenutno uporablja BCrypt, najmočnejši algoritem trenutno podprt s strani PHP-ja. Bo pa tudi posodobljena v prihodnosti za podporo večih algoritmov, kakor bo potrebno. Ustvarjena je bila knjižnica password_compat, ki ponuja vnaprejšnjo kompatibilnost za PHP >= 5.3.7.

Spodaj bomo zgostili niz in nato preverili zgostitev proti novemu nizu. Ker sta naša dva vira nizov različna (‘secret-password’ proti ‘bad-password’), ta prijava ne bo uspela.

<?php
require 'password.php';

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

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

password_hash() poskrbi za soljenje gesel. Sol je shranjena skupaj z algoritmom in »ceno« kot del zgostitve. password_verify() to izloči, da določi, kako preveriti geslo, tako da vam ni potrebno uporabiti ločenega polja v podatkovni bazi, da shranite vaše soli.

Filtriranje podatkov

Nikoli, nikoli ne zaupajte, da se tuji vnosi vnesejo v vašo kodo PHP. Vedno počistite in preverite tuj vnos, preden ga uporabljate v kodi. Funkciji filter_var() in filter_input() lahko počistita tekst in preverita obliko teksta (npr. e-poštni naslov).

Tuj vnos je lahko karkoli: podatki obrazcev $_GET in $_POST, nekatere vrednosti v superglobalni spremenljivki $_SERVER in telo (angl. body) zahtevka HTTP preko fopen('php://input', 'r'). Dobro je vedeti, da tuj vnos ni omejen na poslane podatke iz obrazca s strani uporabnika. Naložene in prenesene datoteke, vrednosti sej, podatki piškotkov in podatki s tretjih strani spletnih servisev so tudi tuji vnosi.

Medtem ko se tuje podatke lahko shrani, kombinira in do njih dostopa kasneje, gre še vedno za tuj vnos. Vsakič, ko procesirate, izpisujete, spojite ali vključite podatke v vašo kodo, se vprašajte, če so bili podatki ustrezno filtrirani in jim lahko zaupate.

Podatki so lahko filtrirani različno na osnovi njihovega namena. Na primer, ko je nefiltriran tuj vnos podan v izpis strani HTML, lahko izvede HTML in JavaScript na vaši strani! To je poznano kot lokacijsko prestopno skriptiranje (angl. cross-site scripting ali XSS) in je lahko zelo nevaren napad. En način, da se izognete XSS, je čiščenje vseh uporabnikovih generiranih podatkov, preden jih izpišete v vašo stran, z odstranitvijo značk HTML s funkcijo strip_tags() ali pretvorbo ubežnih znakov s posebnim pomenom v njihove ustrezne HTML entitete s funkcijama htmlentites() ali htmlspecialchars().

Drug primer je podajanje možnosti, ki se bodo izvedle v ukazni vrstici. To je lahko izjemno nevarno (in je ponavadi slaba ideja), vendar za čiščenje izvedenih ukaznih argumentov lahko uporabite vgrajeno funkcijo escapeshellarg().

Zadnji primer je sprejemanje tujega vnosa, da ugotovite, katero datoteko naložiti iz datotečnega sistema. To je lahko izkoriščeno s spremembo imena datoteke v pot datoteke. Odstraniti morate /, ../, null bajte, ali ostale znake iz poti datoteke, da napadalec ne uspe naložiti skritih, nejavnih ali občutljivih datotek.

Čiščenje

Čiščenje odstrani (ali doda ubežne znake - angl. escaping) nedovoljene ali nevarne znake iz tujega vnosa.

Na primer, preden vključujete vnos v HTML ali ga vnašate v izvorno poizvedbo SQL, bi morali tuj vnos počistiti. Ko uporabljate vezanje parametrov s PDO, bo vnos počistilo za vas.

Včasih je potrebno dovoliti nekatere varne značke HTML v vnosu, ko se ga vključuje v stran HTML. To je zelo težko izvesti in mnogi se tega izogibajo z uporabo ostalih bolj omejenih oblikovanj kot sta Markdown ali BBCode, čeprav za ta namen obstajajo knjižnice z belim seznamom, kot je HTML Purifier.

Poglejte si čistilne filtre

Deserializacija

Nevarno je uporabiti unserialize() za podatke od uporabnikov ali drugih nezaupljivih virov. To lahko omogoči zlonamernim uporabnikom, da sprožijo objekte (z uporabniško definiranimi lastnostmi), katerih destruktorji bodo izvršeni, tudi če objekti sami niso uporabljeni. Zato bi se morali izogibati deserializaciji nezaupljivih podatkov.

Uporabite varno standardno obliko izmenjave podatkov, kot je JSON (prek json_decode in json_encode), če morate uporabniku posredovati serializirane podatke.

Preverjanje

Preverjanje zagotavlja, da je tuj vnos to, kar pričakujete. Na primer, lahko boste želeli preveriti e-poštni naslov, telefonsko številko ali starost pri procesiranju registracijske oddaje.

Poglejte si filtre preverjanja

Konfiguracijske datoteke

Pri ustvarjanju konfiguracijskih datotek za vaše aplikacije, najboljše prakse priporočajo, da se upošteva eno izmed naslednjih metod:

Registracija globalnih spremenljivk

UPOŠTEVAJTE: Od PHP 5.4.0 je bila nastavitev register_globals odstranjena in je ni več možno uporabljati. To je samo vključeno kot opozorilo za kogarkoli v procesu nadgradnje stare aplikacije.

Ko je omogočeno, register_globals nastavitev naredi nekaj tipov spremenljivk (vključno tiste iz $_POST, $_GET in $_REQUEST) na voljo globalnemu področju vaše aplikacije. To lahko hitro vodi v varnostne težave, saj vaša aplikacija ne more efektivno povedati, od kod podatki prihajajo.

Na primer: $_GET['foo'] je tako na voljo preko $foo, kar lahko prepiše spremenljivke, ki so bile opredeljene. Če uporabljate PHP < 5.4.0, se prepričajte, da je register_globals izključen - off.

Poročanje o napakah

Beleženje napak je lahko uporabno v tem, da najdete problematične točke v vaši aplikaciji, vendar lahko tudi razkrije informacije o strukturi aplikacije zunanjemu svetu. Za efektivno zaščito vaše aplikacije pred težavami, ki jih lahko povzroči izpis teh sporočil, morate nastaviti vaš razvojni strežnik drugače od produkcijske različice (v živo).

Razvoj

Za prikaz vsake možne napake med razvojem, nastavite sledeče v vaši datoteki php.ini:

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

Podajanje vrednosti -1 bo prikazalo vsako možno napako, tudi če so novi nivoji ali konstante dodani v bodočih različicah PHP. Konstanta E_ALL se obnaša tudi na tak način od PHP 5.4. - php.net

Konstanta nivoja napak E_STRICT je bila predstavljena v 5.3.0 in ni del E_ALL, čeprav je postala del E_ALL v 5.4.0. Kaj to pomeni? V smislu poročanja vsake možne napake v različici 5.3 pomeni, da morate uporabiti ali -1 ali E_ALL | E_STRICT.

Poročanje vsake možne napake po različicah PHP

Produkcija

Da skrijete napake v vašem produkcijskem okolju, nastavite vašo datoteko php.ini kot:

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

S temi nastavitvami v produkciji, bodo napake še vedno zabeležene v dnevnike napak za spletni strežnik, vendar ne bodo prikazane uporabniku. Za več informacij o teh nastavitvah, si oglejte priročnik PHP:

Nazaj na vrh

Testiranje

Pisanje avtomatiziranih testov za vašo kodo PHP se smatra za najboljšo prakso in lahko vodi k dobro zgrajenim aplikacijam. Avtomatizirani testi so odlično orodje za zagotovitev, da se vaša aplikacija ne zlomi, ko delate spremembe ali dodajate nove funkcionalnosti in ne bi smelo biti ignorirano.

Obstaja več različnih tipov testnih orodij (ali ogrodij), ki so na voljo za PHP in uporabljajo različne pristope - vsa stremijo k izogibanju ročnega testiranja in potrebi po velikih ekipah za zagotavljanje kvalitete, samo da zagotovijo, da zadnje spremembe niso pokvarile trenutne funkcionalnosti.

Testno gnani razvoj

Vir Wikipedia:

Testno voden razvoj (Test Driven Development – TDD, test-first programming, test-driven design, test-first design) je agilen iterativni (po delih) proces razvoja programske kode, kjer programer napiše avtomatizirane teste posameznih programskih enot pred kodo, v kateri nato implementira zahtevano funkcionalnost. Enota je najmanjša možna testna komponenta (metoda, lahko tudi razred). Nato sledi preoblikovanje kode. Cilj testno vodenega razvoja je čista koda, ki deluje, in ne sredstvo za odkrivanje napak (hroščev).

Obstaja več različnih vrst testiranja, ki jih lahko izvedete na vaši aplikaciji.

Testiranje enot

Testiranje enot (angl. unit testing) je programerski pristop, ki zagotovi funkcijam, razredom in metodam, da delujejo kot pričakovano od trenutka, ko jih zgradite, skozi celotno pot razvojnega cikla. S preverjanjem vrednosti, ki vstopajo in izhajajo iz različnih funkcij in metod lahko zagotovite, da notranja logika deluje pravilno. Z uporabo injiciranja odvisnosti in gradnjo modelnih razredov ter nastavkov lahko preverite, da so odvisnosti pravilno uporabljene za še boljšo pokritost testiranja.

Ko izdelate razred ali funkcijo, bi morali narediti test enote za vsako vedenje, ki ga mora imeti. Na zelo osnovnem nivoju bi se morali prepričati, da pride do napake, ko pošljete napačne argumente, in preveriti, da deluje, če pošljete pravilne. To bo pomagalo pri spremembah tega razreda ali funkcije kasneje v razvojnem ciklu, da bo stara funkcionalnost še vedno delovala kot pričakovano. Edina alternativa temu bi bila var_dump() v test.php, kar ni nikoli v redu za gradnjo aplikacije - majhne ali velike.

Drug primer uporabe testov enot je prispevanje odprti kodi. Če lahko napišete test, ki pokaže nedelujočo funkcionalnost (t. j. napako), potem jo popravite in pokažite, da gre test skozi, saj bodo popravki tako veliko bolj sprejeti. Če poganjate projekt, ki sprejema poteg zahtevkov, potem bi morali predlagati to kot zahtevo.

PHPUnit je defakto testno ogrodje za pisanje testov enot za aplikacije PHP, vendar je na voljo tudi precej alternativ:

Integracijsko testiranje

Vir Wikipedia:

Integracijsko testiranje (včasih imenovano integracija in testiranje, skrajšano “I&T”) je faza testiranja programske opreme, v kateri se posamezni moduli programske opreme kombinirajo in testirajo kot skupina. Pojavi se po testiranju enote in pred validacijskim testiranjem. Integracijsko testiranje vzame kot vhod module, ki so bili enotno preizkušeni, jih združi v večje agregate, uporabi teste, opredeljene v načrtu integracijskega testiranja za te agregate, in kot izhod zagotovi integrirani sistem, pripravljen za sistemsko testiranje.

Za integracijsko testiranje se lahko uporabi mnogo enakih orodij, ki so lahko uporabljena za testiranje enot, saj so uporabljeni mnogi enaki principi.

Testiranje funkcionalnosti

Včasih je poznano tudi kot testiranje sprejemljivosti. Testiranje funkcionalnosti sestoji iz uporabe orodij za izdelavo avtomatskih testov, ki dejansko uporabljajo vašo aplikacijo namesto samo preverjanja, da se individualne enote kode obnašajo pravilno in da lahko individualne enote pravilno komunicirajo med seboj. Ta orodja običajno delujejo z uporabo pravih podatkov in simulirajo dejanske uporabnike aplikacije.

Orodja za testiranje funkcionalnosti

Vedenjsko usmerjen razvoj

Na voljo sta dva različna tipa vedenjsko usmerjenega razvoja (angl. behavior driven development - BDD): SpecBDD in StoryBDD. SpecBDD se osredotoča na tehnično obnašanje kode, medtem ko se StoryBdd osredotoča na poslovna ali lastnostna vedenja ali interakcije. PHP ima ogrodja za oba tipa BDD.

Pri StoryBDD pišete zgodbe, ki upisujejo vedenje vaše aplikacije. Te zgodbe se nato lahko požene kot dejanske teste napram vaši aplikaciji. Uporabljeno ogrodje v aplikacijah PHP za StoryBDD je Behat, ki je bil navdihnjen od Rubyjevega projekta Cucumber in implementira Gherkin DSL za opisovanje lastnosti vedenja.

Pri SpecBDD pišete specifikacije, ki opisujejo, kako bi se vaša dejanska koda morala vesti. Namesto testiranja funkcije ali metode, opisujete, kako bi se funkcija ali metoda morala vesti. PHP ponuja PHPSpec ogrodje za ta namen. To ogrodje je navdihnjeno od projekta Rspec za Ruby.

Povezave BDD

Dopolnilna testna orodja

Poleg individualnega testiranja in vedenjsko gnanih ogrodij je na voljo tudi precejšnje število generičnih ogrodij in pomagalnih knjižnic uporabnih za kateregakoli od izbranih prednostnih pristopov.

Povezave orodij

Nazaj na vrh

Strežniki in postavitev

Aplikacije PHP so lahko postavljene in pognane na produkcijskih spletnih strežnikih na mnoge načine.

Platforma kot storitev (PaaS)

PaaS (angl. platform as a service) ponuja sistem in omrežje arhitekture potrebne za poganjanje aplikacij PHP na spletu. To pomeni malo ali nič nastavitev za zagon aplikacij ali ogrodij PHP.

Nedavno je PaaS postala popularna metoda za postavitev, gostovanje in razširjanje aplikacij PHP vseh velikosti. Najdete lahko seznam ponudnikov PHP PaaS “Platform as a Service” v naši sekciji virov.

Virtualni ali namenski strežniki

Če se počutite domače s sistemsko administracijo, ali ste zainteresirani za učenje, virtualni ali namenski strežniki ponujajo celotno kontrolo vašega aplikacijskega produkcijskega okolja.

nginx in PHP-FPM

PHP preko PHP-jevega vgrajenega FastCGI procesnega upravljalnika (FPM) gre res lepo skupaj s strežnikom nginx, ki je lahek in dobro zmogljiv spletni strežnik. Porabi manj spomina kot Apache in boljše ravna s sočasnimi zahtevki. To je še posebej pomembno na virtualnih strežnikih, ki nimajo na voljo veliko spomina.

Apache in PHP

PHP in Apache imata za sabo dolgo zgodovino. Apache je divje nastavljiv in ima na voljo mnogo modulov za razširitev funkcionalnosti. Je priljubljena izbira za skupne strežnike in enostavna namestitev za ogrodja PHP in odprtokodne aplikacije, kot je WordPress. Na žalost Apache privzeto uporabi več virov kot nginx in ne zmore toliko istočasnih obiskovalcev.

Apache ima nekaj možnih nastavitev za poganjanje PHP. Najbolj pogosta in enostavna za namestitev je prefork MPM z mod_php. Medtem ko ni najbolj spominsko učinkovit, je pa najbolj enostaven za delo in uporabo. To je verjetno najboljša izbira, če se ne želite poglabljati preveč globoko v aspekte strežniške administracije. Upoštevajte, da če uporabljate mod_php, morate uporabiti prefork MPM.

Alternativno, če želite stisniti več zmogljivosti in stabilnosti iz Apacheja, potem lahko izkoristite enak sistem FPM kot nginx in pognati worker MPM ali event MPM z mod_fastcgi ali mod_fcgid. Ta nastavitev bo bistveno bolj spominsko učinkovita in hitrejša, vendar je potrebno več dela za vzpostavitev.

Če poganjate Apache 2.4 ali novejši, lahko uporabite mod_proxy_fcgi, da dobite enostavno nastavljivo zmogljivost.

Skupni strežniki

PHP se lahko zahvali skupnim strežnikom za njegovo popularnost. Težko je najti gostitelja brez nameščenega PHP, vendar bodite prepričani, da je zadnja različica. Skupni strežniki dovoljujejo vam ali ostalim razvijalcem, da se postavi spletno stran na eno napravo. Prednost tega je, da je to postalo poceni blago. Slabost pa je, da nikoli ne veste, kakšno navlako bodo vaši sosedje ustvarili; nalagalni čas strežnika in odprte varnostne luknje so glavna zaskrbljenost. Če si proračun vašega strežnika lahko privošči izogib skupnih strežnikov, je to dobro.

Prepričajte se, da vaši deljeni strežniki ponujajo zadnje različice PHP.

Gradnja in postavitev vaše aplikacije

Če ugotovite, da delate ročne spremembe podatkovne baze ali poganjate vaše teste ročno, preden posodabljate vaše datoteke (ročno), ponovno premislite! Z vsakim dodatnim ročnim opravilom potrebnim za postavitev nove verzije vaše aplikacije, se možnosti za potencialno usodno napako povečajo. Ali če imate opravka z enostavno posodobitvijo, podrobnim procesom gradnje ali celo strategijo zvezne integracije, je avtomatizacija gradnje vaš prijatelj.

Med opravili, ki jih želite avtomatizirati, so:

Orodja za namestitev

Orodja za namestitev lahko opišemo kot zbirko skriptov, ki opravljajo pogosta opravila namestitve programske opreme. Orodje za namesitev ni del vaše aplikacije, vendar deluje na vaši aplikaciji od »zunaj«.

Na voljo je ogromno odprtokodnih orodij, ki so na voljo za pomoč pri avtomatizirani gradnji in namestitvi. Nekatera so napisana v PHP, nekatera ne. To vas ne bi smelo ovirati pri njihovi uporabi, če so bolj primerna za določeno nalogo. Tu je nekaj primerov:

Phing lahko krmili vaše procese pakiranja, postavitve ali testiranja iz postavitvene datoteke XML. Phing (ki je osnovan na Apache Ant) ponuja bogat nabor opravil, ki so ponavadi potrebna za namestitev ali posodobitev spletne aplikacije, in se ga lahko razširi z dodatnimi opravili po meri, napisanimi v PHP. Je stabilno in močno orodje, ki je na voljo že dolgo časa, vendar se ga lahko dojema za nekoliko staromodno zaradi načina obravnave konfiguracije (datoteke XML).

Capistrano je sistem za programerje z nadaljevalnim do naprednim znanjem, da lahko izvajajo ukaze na strukturiran, ponovljiv način na eni ali več oddaljenih naprav. Je prednastavljen za namestitev aplikacij Ruby on Rails, čeprav z njim lahko uspešno nameščate sisteme PHP. Uspešna uporaba Capistrana zavisi na praktičnem znanju Rubyja in Rake.

Ansistrano je skupek vlog Ansible za enostaven proces nalaganja (namestitev in povrnitev) za skriptne aplikacije kot so PHP, Python in Ruby. Gre za Ansiblov prenos za Capistrano. Uporabljen je bil že pri kar nekaj podjetjih, ki uporabljajo PHP.

Deployer je orodje za namestitev napisano v PHP. Je enostavno in funkcionalno. Lastnosti vključujejo poganja opravil vzporedno, opravljanje atomske namestitve in obdržanje konsistentnosti med strežniki. Na voljo so recepti pogostih opravil za Symfony, Laravel, Zend Framework in Yii. Younes Rafiejev članek Easy Deployment of PHP Applications with Deployer je odličen vodnik za namestiev vaše aplikacije s tem orodjem.

Magallanes je drugo orodje napisano v PHP z enostavno konfiguracijo v datotekah YAML. Podpira več strežnikov in okolij, atomske namestitve in ima vgrajena opravila, ki jih lahko uporabite pri pogostih orodjih in ogrodjih.

Nadaljnje branje

Strežniške provizije

Upravljanje in konfiguracija strežnikov je lahko zastrašujoče opravilo pri večih strežnikih. Na voljo so orodja za ravnanje s tem, tako da lahko avtomatizirate vašo infrastrukturo in zagotovite, da imate pravilno nastavljene strežnike. Pogosto se integrirajo z večjimi ponudniki oblačnega gostovanja (Amazon Web Services, Heroku, DigitalOcean itd.) za upravljanje instanc, kar naredi razširjanje aplikacije veliko enostavnejše.

Ansible je orodje, ki upravlja vašo infrastrukturo preko datotek YAML. Je enostaven za začeti in lahko upravlja kompleksne in večje apllikacije. Na voljo je API za upravljanje oblačnih instanc in lahko jih upravlja preko dinamičnega inventarja z uporabo določenih orodij.

Puppet je orodje, ki ima svoj lasten jezik in vrste datotek za upravljanje strežnikov in konfiguracij. Lahko se ga uporabi v namestitvi master/odjemalec ali pa se ga uporablja v načinu »brez masterja« (angl. master-less). V načinu master/odjemalec, bodo odjemalci raziskali osrednje masterje za novo konfiguracijo po nastavljenih intervalih in se posodobili, če je potrebno. V načinu master-less, lahko pošljete spremembe vašim vozliščem.

Chef je močno, na Rubyju osnovano, sistemsko ogrodje za integracijo, s katerim lahko zgradite vaše celotno strežniško okolje ali virtualne naprave. Dobro se integrira z Amazon Web Services preko njihove storitve imenovane OpsWorks.

Nadaljnje branje:

Zvezna integracija

Zvezna integracija je praksa razvoja programske opreme, pri kateri člani ekipe pogosto integrirajo svoje delo, običajno vsaka oseba integrira vsaj enkrat na dan, kar vodi do večkratnih integracij na dan. Mnoge ekipe ugotovijo, da ta pristop bistveno zmanjša težave pri integraciji in ekipi omogoča hitrejši razvoj kohezivne programske opreme.

– Martin Fowler

Obstaja več različnih poti za implementacijo zvezne integracije za PHP. Travis CI je naredil odlično delo zvezne integracije, zaradi česar je realnost tudi za manjše projekte. Travis CI je gostovan servis zvezne integracije. Integrira se ga lahko z GitHubom in ponuja podporo za mnoge jezike, tudi za PHP. GitHub ima poteke dela zvezne integracije preko t. i. GitHub Actions.

Nadaljnje branje:

Nazaj na vrh

Virtualizacija

Poganjanje vaše aplikacije v različnih okoljih v razvoju in produkciji lahko pripelje do pojavljanja čudnih hroščev, ko jo naložite v produkcijo. Zapleteno je tudi imeti posodobljena različna razvojna okolja z enakimi različicami vseh uporabljenih knjižnic, ko delate z ekipo razvijalcev.

Če razvijate na Windows in nalagate na Linux (ali na karkoli ne-Windows) ali razvijate v ekipi, bi morali premisliti o uporabi virtualne naprave. Zveni zapleteno, vendar poleg znanih virtualizacijskih okolj kot sta VMware ali VirtualBox, so na voljo dodatna orodja, ki vam lahko pomagajo naložiti virtualno okolje v nekaj enostavnih korakih.

Vagrant

Vagrant vam pomaga zgraditi vaše virtualne naprave na vrhu znanih virtualnih okolij in nastavi jih na osnovi ene nastavitvene datoteke. Te naprave se lahko nastavi ročno ali pa uporabite oskrbovalno (angl. provisioning) programsko opremo, kot sta Puppet ali Chef, ki to naredita za vas. Oskrbovanje osnovne naprave je odličen način za zagotovitev, da je več naprav nameščenih v identični obliki, in odstrani potrebo po vzdrževanju komplicirane namestitve seznama ukazov. Vašo osnovno napravo lahko tudi odstranite in jo ponovno kreirate brez mnogih ročnih korakov, kar omogoča enostavno novo namestitev.

Vagrant naredi skupne mape, ki se uporabljajo za deljenje vaše kode med vašim gostiteljem in vašo virtualno napravo, kar pomeni, da lahko naredite in uredite vaše datoteke na vaši gostiteljski napravi in nato poženete kodo znotraj virtualne naprave.

Docker

Docker - lahka alternativa polni virtualni napravi - se tako imenuje, ker gre za »kontejnerje«. Kontejner je gradnik, ki v najenostavnejšem primeru opravlja posamezno specifično nalogo, npr. poganja spletni strežnik. Slika je paket, ki jo uporabite za gradnjo kontejnerja - Docker ima repozitorij poln slik.

Običajna aplikacija LAMP ima lahko tri kontejnerje: spletni strežnik, proces PHP-FPM in MySQL. Kot pri deljenih mapah pri Vagrantu, lahko pustite datoteke vaše aplikacije, kjer so, in poveste Dockerju, kje jih najde.

Kontejnerje lahko generirate iz ukazne vrstice (glejte primer spodaj) ali zaradi enostavnosti vzdrževanja, zgradite datoteko docker-compose.yml za vaš projekt, kjer se določi katere ustvariti in kako komunicirajo med seboj.

Docker lahko pomaga, če razvijate več spletnih strani in želite ločitev, ki pride z namestitvijo vsake na svoji lastni virtualni napravi, vendar nimate potrebnega prostora na disku ali časa, da imate vse posodobljeno. Je učinkovito: namestitev in prenosi so hitrejši, shraniti morate edino eno kopijo vsake slike ne glede na to koliko pogostokrat je uporabljena. Kontejnerji potrebujejo manj RAM-a in si delijo isto jedro operacijskega sistema, tako da lahko poganjate več strežnikov istočasno, kjer zaustavitev in zagon vzame nekaj sekund in ni potrebno čakati, da se strežnik ponovno zažene.

Primer: Poganjanje vaše aplikacije PHP v Dockerju

Po namestitvi Dockerja na vašo napravo lahko poženete spletni strežnik z enim ukazom. Sledeče bo preneslo polno funkcionalno namestitev Apache z zadnjo verzijo PHP, preslikalo /path/to/your/php/files v vrhnjo mapo, kar lahko pogledate na http://localhost:8080:

docker run -d --name my-php-webserver -p 8080:80 -v /path/to/your/php/files:/var/www/html/ php:apache

To bo inicializiralo in pognalo vaš kontejner. Možnost -d ga požene v ozadju. Da ga zaustavite in zaženete, enostavno poženite docker stop my-php-webserver in docker start my-php-webserver (drugi parametri niso ponovno potrebni).

Izvedite več o Dockerju

Ukaz zgoraj prikazuje hiter način pogona osnovnega strežnika. Obstaja še več, kar lahko naredite (in tisoče vnaprej zgrajenih slik na Docker Hub). Vzamite si čas, da spoznate terminologijo in preberite uporabniški vodnik Docker, da ga bolje spoznate in ne poganjate naključne kode, ki ste jo prenesli brez preverjanja, če je varna - neuradne slike lahko nimajo najnovejših varnostnih popravkov. Če ste v dvomih, se držite uradnih repozitorijev.

Stran PHPDocker.io bo avtomatsko zgenerirala vse datoteke, ki jih potrebujete za polno opremljen sklad LAMP/LEMP, vključno z vašo izbiro različice PHP in razširitev.

Nazaj na vrh

Predpomnjenje

PHP je precej hiter sam po sebi, vendar ozko grlo se lahko pojavi, ko delate oddaljene povezave, nalagate datoteke itd. Na srečo so na voljo različna orodja, ki pohitrijo določene dele vaše aplikacije ali zmanjšajo čas, ki jih ta različna časovno potratna opravila potrebujejo za izvajanje.

Predpomnilnik ukazne kode

Ko se datoteka PHP izvede, mora biti najprej prevedena v ukazno kodo - angl. opcode (navodila strojnega jezika za CPU). Če je izvorna koda nespremenjena, bo ukazna koda enaka, tako da ta korak sestavljanja postane odvečen vir za CPU.

Predpomnilnik ukazne kode (angl. opcode cache) preprečuje odvečno sestavljanje s shranjevanjem ukazne kode v spomin in jo ponovno uporabi pri zaporednih klicih. Običajno se najprej preveri podpis ali čas spremembe datoteke, če je prišlo do kakšnih sprememb.

Verjetno je, da bo predpomnilnik ukazne kode naredil opazno izboljšanje hitrosti vaše aplikacije. Od PHP 5.5 je na voljo vgrajeni Zend OPCache. Odvisno od vašega paketa/distribucije PHP je običajno privzeto vključen - preverite opcache.enable in izpis phpinfo(), da se prepričate. Za prejšnje različice je na voljo PECL razširitev.

Preberite več o predpomnilnikih ukazne kode:

Predpomnjenje objektov

Pride čas, ko je koristno predpomniti individualne objekte v vašo kodo, kot so podatki, ki so prepomembni, da bi jih dobili iz ali klicali v podatkovno bazo, kjer se rezultat verjetno ne bo spremenil. Za predpomnjenje objektov lahko uporabite programsko opremo, da shrani te dele podatkov v spomin pri izjemno hitrih kasnejših klicih. Če shranite te elemente v podatkovno shrambo, ko naredite poizvedbo zanje, jih potem lahko potegnite direktno iz predpomnilnika za le-te zahtevke. Dobite lahko izjemno izboljšavo v zmogljivosti kot tudi zmanjšanje obremenitve na vaše strežnike podatkovne baze.

Mnoge popularne rešitve predpomnilnikov ukazne kode, vam omogočajo tudi predpomnjenje podatkov po meri. Tako, da je še večji razlog, da jih izkoristite. Tako APCu kot WinCache oba ponujata API-je, da shranite podatke iz vaše PHP kode v njihov spomin predpomnilnika.

Najobičajnejša uporabljana sistema spominsko objektnega predpomnjenja sta APCu in memcached. APCu je odlična izbira za objektno predpomnjenje, vključuje enostaven API za dodajanje vaših podatkov v njihov spomin predpomnilnika in je zelo enostaven za nastaviti in uporabiti. Realna omejitev APCu-ja je, da je vezan na strežnik, na katerega je nameščen. Memcached po drugi strani je nameščen kot ločena storitev in se do nje lahko dostopa preko omrežja, kar pomeni, da lahko shranite objekte v hiper-hitro podatkovno shrambo na centralni lokaciji in mnoge različne sisteme lahko potegnete iz nje.

Upoštevajte, da ko poganjate PHP kot aplikacijo (Fast-)CGI znotraj vašega spletnega strežnika, bo imel vsak proces PHP namesto tega svoj predpomnilnik, to pomeni, da podatki APCu ne bodo deljeni med vašimi delovnimi procesi. V teh primerih je namesto tega dobro premisliti o uporabi predpomnilnika memcached, saj ni vezan na procese PHP.

V omrežnih nastavitvah APCu bo običajno prekašal memcached, kar se tiče dostopne hitrosti, vendar memcached bo sposoben hitrejšega in širšega razširjanja. Če ne pričakujete, da boste imeli mnoge strežnike za poganjanje vaše aplikacije, ali pa ne potrebujete dodatnih lastnosti, ki jih memcached ponuja, potem je APCu verjetno najboljša izbira za predpomnjenje objektov.

Primer logike z uporabo APCu:

<?php
// check if there is data saved as 'expensive_data' in cache
$data = apcu_fetch('expensive_data');
if ($data === false) {
    // data is not in cache; save result of expensive call for later use
    apcu_add('expensive_data', $data = get_expensive_data());
}

print_r($data);

Upoštevajte, da pred PHP 5.5, je obstala razširitev APC, ki je ponujala tako predpomnilnik objektov kot tudi predpomnilnik ukazne kode. Novejši APCu je projekt, ki je prinesel APC-jev predpomnilnik objektov v PHP 5.5+, odkar ima PHP sedaj vgrajeni predpomnilnik ukazne kode (OPcache).

Izvedite več o popularnih sistemih predpomnilnikov objektov:

Nazaj na vrh

Dokumentiranje vaše kode

PHPDoc

PHPDoc je neformalni standard za komentiranje PHP kode. Na voljo je veliko različnih značk. Celoten seznam značk in primerov se lahko najde v priročniku PHPDoc.

Spodaj je primer, kako lahko dokumentirate razred z nekaj metodami;

<?php
/**
 * @author A Name <a.name@example.com>
 * @link https://www.phpdoc.org/docs/latest/index.html
 */
class DateTimeHelper
{
    /**
     * @param mixed $anything Anything that we can convert to a \DateTime object
     *
     * @throws \InvalidArgumentException
     *
     * @return \DateTime
     */
    public function dateTimeFromAnything($anything)
    {
        $type = gettype($anything);

        switch ($type) {
            // Some code that tries to return a \DateTime object
        }

        throw new \InvalidArgumentException(
            "Failed Converting param of type '{$type}' to DateTime object"
        );
    }

    /**
     * @param mixed $date Anything that we can convert to a \DateTime object
     *
     * @return void
     */
    public function printISO8601Date($date)
    {
        echo $this->dateTimeFromAnything($date)->format('c');
    }

    /**
     * @param mixed $date Anything that we can convert to a \DateTime object
     */
    public function printRFC2822Date($date)
    {
        echo $this->dateTimeFromAnything($date)->format('r');
    }
}

Dokumentacija za razred kot celoto ima najprej značko @author in značko @link. Značka @author je uporabljena za dokumentiranje avtorja kode in je lahko ponovljena za dokumentiranje večih avtorjev. Značka @link je uporabljena za povezavo na stran, ki označuje zvezo med spletno stranjo in kodo.

Znotraj razreda ima prva metoda značko @param, ki dokumentira tip, ime in opis parametra, ki je bil podan metodi. Dodatno ima znački @return in @throws za dokumentiranje vrnjenega tipa in katerekoli izjeme, ki jih lahko vrže.

Druga in tretja metoda sta zelo podobni in imata eno značko @param, kot jo ima prva metoda. Pomembna razlika med blokom dokumentacije druge in tretje metode, je vključevanje/izključevanje značke @return. @return void nas eksplicitno informira, da nič ne vrne, zgodovinska izpustitev @return void stavka ima tudi rezultate v isti akciji, ki ne vrne ničesar.

Nazaj na vrh

Viri

Iz izvora

Sledite ljudem

Ko začenjate, je težko najti zanimive in razgledane člane skupnosti PHP. Seznam članov skupnosti PHP za začetek lahko najdete na:

Ponudniki PHP PaaS

Ogrodja

Namesto ponovnega odkrivanja tople vode, mnogi razvijalci PHP uporabljajo ogrodja, da zgradijo spletne aplikacije. Ogrodja abstraktirajo mnoge nizko nivojske skrbi in ponujajo ustrežljive vmesnike enostavne za uporabo, da se dokonča pogosta opravila.

Ne potrebujete uporabljati ogrodja za vsak projekt. Včasih je preprosti PHP pravilen način, vendar če pa potrebujete ogrodje, potem so na voljo trije glavni tipi:

Mikro ogrodja so v osnovi ovoj za usmeritev zahtevka HTTP v povratni klic, krmilnik, metodo itd. kot hitro je mogoče in včasih pridejo z nekaj dodatnimi knjižnicami, da pomagajo razvijanju, kot so osnovna ovijanja podatkovne baze in podobno. Uporabljeni so očitno za gradnjo oddaljenih storitev HTTP.

Mnoga ogrodja dodajo veliko število lastnosti na tisto, kar je na voljo v mikro ogrodju; ta se imenujejo ogrodja s celostno rešitvijo (angl. full-stack frameworks). Ta pogosto v paketu vsebujejo ORM, pakete za preverjanje pristnosti itd.

Komponentno osnovana ogrodja so zbirka specializiranih in samonamenskih knjižnic. Raznolika komponentno osnovana ogrodja se lahko uporabljajo skupaj, da se tvori mikro ali univerzalno ogrodje.

Komponente

Kot že omenjeno zgoraj, so komponente še en pristop k skupnemu cilju izdelave, distribucije in implementacije skupno deljene kode. Obstajajo različni komponentni repozitoriji, glavna med njimi sta dva:

Oba od teh repozitorijev imata orodja za ukazno vrstico povezano z njimi, da pomagata namestiti in nadgraditi procese in sta bolj podrobno razložena v sekciji upravljanja paketov.

Na voljo so tudi komponentno osnovana ogrodja, ki vam dovoljujejo uporabiti njihove komponente z minimalnimi ali nič zahtevami. Na primer uporabite lahko paket preverjanja FuelPHP, brez potrebe po uporabi samega ogrodja FuelPHP. Te projekti so v bistvu samo dodaten repozitorij za ponovno uporabne komponente:

Laravelove komponente Illuminate bodo postale bolj nevezane v ogrodju Laravel. Za sedaj so tu zabeležene samo komponente, ki so lahko najboljše nevezne.

Ostali uporabni viri

Plonk listki

Več najboljših praks

Novice skupnosti PHP in spletnega razvoja

Lahko se naročite na tedenske e-novice, da ste obveščeni o novih knjižnicah, najnovejših novicah, dogodkih in splošnih obvestilih, kot tudi dodatnih virih, ki so objavljeni vsake toliko časa:

Vesolje PHP

Video vaje

Kanali YouTube

Plačljivi videi

Knjige

Za PHP je na voljo mnogo knjig; na žalost so nekatere sedaj precej stare in niso več točne. Posebej se izogibajte knjig na temo »PHP 6«, različica, ki ne bo nikoli obstajala. Naslednja večja različica PHP po 5.6 je bila »PHP 7«, delno zaradi tega.

Ta sekcija ima cilj imeti posodobljen dokument za priporočene knjige o razvoju PHP na splošno. Če želite, da se doda vašo knjigo, pošljite zahteveg potega (angl. pull request - PR) in bo pregledana za relevantnost.

Brezplačne knjige

Plačljive knjige

Nazaj na vrh

Skupnost

Skupnost PHP je tako raznolika, kot je tudi velika in njeni člani so pripravljeni podpirati nove programerje PHP. Premislite o pridružitvi vaši lokalni uporabniški skupini PHP (angl. PHP User Group - PUG) ali obiščite večje konference PHP, da se naučite več o najboljših praksah prikazanih tu. Lahko se priklopite tudi na kanal IRC #phpc irc.freenode.com in sledite @phpc na računu Twitter ali Mastodonu. Pojdite tja, spoznajte nove razvijalce, naučite se nove teme in predvsem si ustvarite nove prijatelje! Ostali viri skupnosti vključujejo StackOverflow.

Preberite uraden koledar dogodkov PHP

Uporabniške skupine PHP

Če živite v večjem mestu, je verjetnost, da blizu obstaja uporabniška skupina PHP. Enostavno lahko najdete vašo lokalno skupino PUG na seznamu uporabniških skupin na php.net, ki je osnovan na PHP.ug. Alternativni viri so lahko Meetup.com ali iščite php user groups near me z uporabo vašega priljubljenega iskalnika (t. j. Google). Če živite v manjšem mestu, lahko da lokalna PUG ne obstaja. V tem primeru jo kar pričnite!

Posebna omemba je potrebna dvema globalnima uporabniškima skupinama: NomadPHP in PHPWomen. NomadPHP ponuja dvakrat mesečeno srečanja uporabnikov na spletu s predstavitvami nekaterih najboljših govornikov v skupnosti PHP. PHPWomen je ne-eksluzivna uporabniška skupina prvotno targetirana ženskam v svetu PHP. Članstvo je odprto za vsakogar, ki podpira bolj raznoliko skupnost. PHPWomen ponuja omrežje za podporo, mentorstvo in izobraževanje ter v splošnem promovira izdelavo »ženskam prijazne« in profesionalne atomsfere.

Preberite o uporabniških skupinah na PHP Wiki

Konference PHP

Skupnost PHP gosti tudi večje regionalne in nacionalne konference v mnogih državah po svetu. Dobro znani člani skupnosti PHP običajno govorijo na teh večjih dogodkih, tako da je to odlična priložnost, da se naučite direktno od vodilnih v industriji.

Najdite konferenco PHP

Slončki PHP (elePHPanti)

ElePHPant je prikupna maskota projekta PHP v obliki slončka. Prvotno jo je leta 1998 za projekt PHP oblikoval Vincent Pontier - spiritualni oče tisočerih elePHPantov po svetu in 10 let kasneje so se rodile tudi prikupne plišaste igračke. Sedaj so elePHPanti prisotni na mnogih konferencah PHP in pri mnogih PHP razvijalcih za njihovimi računalniki so namenjeni zabavi in inspiraciji.

Intervju Vincent Pontier