portaldacalheta.pt
  • Hlavná
  • Životný Cyklus Produktu
  • Iné
  • Agilný Talent
  • Projektový Manažment
Technológie

Buggy PHP Code: 10 najčastejších chýb, ktoré vývojári PHP robia



Vďaka PHP je relatívne ľahké vybudovať webový systém, čo je veľkou príčinou jeho popularity. Ale napriek jeho ľahkému použitiu PHP sa vyvinulo do dosť sofistikovaného jazyka s mnohými štruktúrami, nuansami a jemnosťami, ktoré môžu vývojárov pohrýzť, čo vedie k hodinám ladenia za vlasy. Tento článok zdôrazňuje desať najbežnejších chýb Vývojári PHP treba si dať pozor.

Bežná chyba č. 1: Ponechanie visiacich odkazov na polia po foreach slučky

Neviete, ako používať slučky foreach v PHP? Používanie referencií v foreach slučky môžu byť užitočné, ak chcete pracovať s každým prvkom v poli, ktoré iterujete. Napríklad:



$arr = array(1, 2, 3, 4); foreach ($arr as &$value) { $value = $value * 2; } // $arr is now array(2, 4, 6, 8)

Problém je v tom, že ak si nedáte pozor, môže to mať aj niektoré nežiaduce vedľajšie účinky a následky. Konkrétne vo vyššie uvedenom príklade po vykonaní kódu $value zostane v rozsahu a bude obsahovať odkaz na posledný prvok v poli. Následné operácie zahŕňajúce $value by preto mohlo nechtiac skončiť úpravou posledného prvku v poli.



Hlavná vec, ktorú treba pamätať, je foreach nevytvára rozsah. Teda $value vo vyššie uvedenom príklade je a odkaz v hornom rozsahu skriptu. Pri každej iterácii foreach nastaví odkaz na ďalší prvok $array. Po dokončení cyklu teda $value stále ukazuje na posledný prvok $array a zostáva v rozsahu pôsobnosti.



Tu je príklad druhu úhybných a mätúcich chýb, ku ktorým to môže viesť:

$array = [1, 2, 3]; echo implode(',', $array), ' '; foreach ($array as &$value) {} // by reference echo implode(',', $array), ' '; foreach ($array as $value) {} // by value (i.e., copy) echo implode(',', $array), ' ';

Vyššie uvedený kód poskytne nasledujúce výstupy:



1,2,3 1,2,3 1,2,2

Nie, nejde o preklep. Posledná hodnota v poslednom riadku je skutočne 2, nie 3.

Prečo?



Po prechode prvým foreach slučka, $array zostáva nezmenený, ale, ako je vysvetlené vyššie, $value je ponechaný ako visiaci odkaz na posledný prvok v $array (od tej doby foreach sprístupnená slučka $value od odkaz ).

Vo výsledku, keď prechádzame druhým foreach slučka, zdá sa, že sa vyskytujú „divné veci“. Konkrétne od $value je teraz prístupný podľa hodnoty (tj kópia ), foreach kópie každé postupné $array prvok do $value v každom kroku slučky. Výsledkom je, že čo sa stane počas každého kroku druhého foreach slučka:



  • Pass 1: Kópie $array[0] (tj. „1“) do $value (čo je odkaz na $array[2]), takže $array[2] teraz sa rovná 1. Takže $array teraz obsahuje [1, 2, 1].
  • Pass 2: Kópie $array[1] (tj. „2“) do $value (čo je odkaz na $array[2]), takže $array[2] teraz sa rovná 2. Takže $array teraz obsahuje [1, 2, 2].
  • Pass 3: Kópie $array[2] (ktoré sa teraz rovná „2“) do $value (čo je odkaz na $array[2]), takže $array[2] stále sa rovná 2. Takže $array teraz obsahuje [1, 2, 2].

Ak chcete stále využívať výhody použitia referencií v foreach slučky bez rizika vzniku týchto druhov problémov, volajte unset() na premennej, bezprostredne za foreach slučka, na odstránenie referencie; napr .:

$arr = array(1, 2, 3, 4); foreach ($arr as &$value) { $value = $value * 2; } unset($value); // $value no longer references $arr[3]

Spoločná chyba č. 2: nedorozumenie isset() správanie

Napriek svojmu názvu isset() nielenže vráti hodnotu false, ak položka neexistuje, ale - vráti tiež false pre null hodnoty .



Toto správanie je problematickejšie, ako by sa na prvý pohľad mohlo zdať, a je častým zdrojom problémov.

Zvážte nasledovné:



$data = fetchRecordFromStorage($storage, $identifier); if (!isset($data['keyShouldBeSet']) { // do something here if 'keyShouldBeSet' is not set }

Autor tohto kódu pravdepodobne chcel skontrolovať, či keyShouldBeSet bolo nastavené v $data. Ako už bolo uvedené, isset($data['keyShouldBeSet']) bude tiež return false if $data['keyShouldBeSet'] bol nastavená, ale bola nastavená na null. Vyššie uvedená logika je teda chybná.

js previesť časovú pečiatku na dátum

Tu je ďalší príklad:

if ($_POST['active']) { $postData = extractSomething($_POST); } // ... if (!isset($postData)) { echo 'post not active'; }

Vyššie uvedený kód predpokladá, že ak $_POST['active'] vráti true, potom postData budú nevyhnutne nastavené, a preto isset($postData) vráti true. Vyššie uvedený kód teda predpokladá, že iba tak isset($postData) vráti false je ak $_POST['active'] vrátené false tiež.

Nie.

Ako bolo vysvetlené, isset($postData) vráti tiež false ak $postData bol nastavený na null. Preto je možné pre isset($postData) vrátiť sa false aj keď $_POST['active'] vrátené true. Vyššie uvedená logika je teda chybná.

A mimochodom, ako bočný bod, ak bolo zámerom vo vyššie uvedenom kóde skutočne znova skontrolovať, či $_POST['active'] vrátil sa true, spoliehal sa na isset() pretože to bolo v každom prípade zlé rozhodnutie o kódovaní. Namiesto toho by bolo lepšie znova skontrolovať $_POST['active']; tj .:

if ($_POST['active']) { $postData = extractSomething($_POST); } // ... if ($_POST['active']) { echo 'post not active'; }

Pre prípady však kde je dôležité skontrolovať, či bola premenná skutočne nastavená (tj. aby sa rozlišovalo medzi premennou, ktorá nebola nastavená, a premennou, ktorá bola nastavená na null), array_key_exists() metóda je oveľa robustnejšie riešenie.

Prvý z vyššie uvedených dvoch príkladov by sme mohli napríklad prepísať takto:

$data = fetchRecordFromStorage($storage, $identifier); if (! array_key_exists('keyShouldBeSet', $data)) { // do this if 'keyShouldBeSet' isn't set }

Navyše kombináciou array_key_exists() s get_defined_vars() , môžeme spoľahlivo skontrolovať, či bola alebo nebola nastavená premenná v aktuálnom rozsahu:

if (array_key_exists('varShouldBeSet', get_defined_vars())) { // variable $varShouldBeSet exists in current scope }

Bežná chyba č. 3: Zmätok v návrate podľa referencie a podľa hodnoty

Zvážte tento útržok kódu:

class Config { private $values = []; public function getValues() { return $this->values; } } $config = new Config(); $config->getValues()['test'] = 'test'; echo $config->getValues()['test'];

Ak spustíte vyššie uvedený kód, získate nasledovné:

PHP Notice: Undefined index: test in /path/to/my/script.php on line 21

Čo je zle?

Problém je v tom, že vyššie uvedený kód zamieňa vracajúce sa polia odkazom s vracajúcimi sa poliami podľa hodnoty. Pokiaľ výslovne nepoviete PHP, aby vrátilo pole pomocou referencie (tj. Pomocou &), PHP štandardne vráti pole „podľa hodnoty“. To znamená, že a kópia poľa sa vráti a preto volaná funkcia a volajúci nebudú mať prístup k rovnakej inštancii poľa.

Takže vyššie uvedená výzva na getValues() vracia a kópia z $values pole skôr ako odkaz na ňu. Z tohto dôvodu si preštudujme dva kľúčové riadky z vyššie uvedeného príkladu:

// getValues() returns a COPY of the $values array, so this adds a 'test' element // to a COPY of the $values array, but not to the $values array itself. $config->getValues()['test'] = 'test'; // getValues() again returns ANOTHER COPY of the $values array, and THIS copy doesn't // contain a 'test' element (which is why we get the 'undefined index' message). echo $config->getValues()['test'];

Jednou z možných opráv by bolo uložiť prvú kópiu $values pole vrátené getValues() a potom s touto kópiou následne pracovať; napr .:

$vals = $config->getValues(); $vals['test'] = 'test'; echo $vals['test'];

Tento kód bude fungovať dobre (tj. Bude vydávať test bez generovania správy „nedefinovaného indexu“), ale v závislosti od toho, čo sa snažíte dosiahnuť, môže alebo nemusí byť tento prístup adekvátny. Vyššie uvedený kód konkrétne nezmení pôvodný $values pole. Takže ak ty robiť ak chcete, aby vaše úpravy (napríklad pridanie prvku „test“) ovplyvnili pôvodné pole, musíte namiesto toho upraviť getValues() funkcia vrátiť a odkaz do $values samotné pole. To sa deje pridaním & pred názvom funkcie, čím naznačuje, že by mala vrátiť referenciu; tj .:

class Config { private $values = []; // return a REFERENCE to the actual $values array public function &getValues() { return $this->values; } } $config = new Config(); $config->getValues()['test'] = 'test'; echo $config->getValues()['test'];

Výstupom bude podľa očakávania test.

Aby to však nebolo tak jednoduché, zvážte radšej nasledujúci útržok kódu:

class Config { private $values; // using ArrayObject rather than array public function __construct() { $this->values = new ArrayObject(); } public function getValues() { return $this->values; } } $config = new Config(); $config->getValues()['test'] = 'test'; echo $config->getValues()['test'];

Ak ste uhádli, že by to malo za následok rovnakú chybu „nedefinovaného indexu“ ako naša predchádzajúca array napríklad si sa mýlil. V skutočnosti, toto kód bude fungovať dobre. Dôvod je ten, že na rozdiel od polí, PHP vždy odovzdáva objekty odkazom . (ArrayObject je objekt SPL, ktorý úplne napodobňuje použitie polí, ale funguje ako objekt.)

Ako ukazujú tieto príklady, v PHP nie je vždy úplne zrejmé, či máte na mysli kópiu alebo odkaz. Je preto nevyhnutné porozumieť týmto predvoleným vlastnostiam (tj. Premenné a polia sa odovzdávajú hodnotou; objekty sa odovzdávajú odkazom) a tiež starostlivo skontrolovať dokumentáciu API pre funkciu, ktorú voláte, aby ste zistili, či vracia hodnotu, a kópia poľa, odkaz na pole alebo odkaz na objekt.

Všetko, čo bolo povedané, je dôležité poznamenať, že prax vrátenia odkazu na pole alebo ArrayObject je všeobecne niečo, čomu by ste sa mali vyhnúť, pretože poskytuje volajúcemu možnosť upravovať súkromné ​​údaje inštancie. Toto „letí do tváre“ zapuzdreniu. Namiesto toho je lepšie použiť starý štýl „getre“ a „setre“, napr .:

class Config { private $values = []; public function setValue($key, $value) { $this->values[$key] = $value; } public function getValue($key) { return $this->values[$key]; } } $config = new Config(); $config->setValue('testKey', 'testValue'); echo $config->getValue('testKey'); // echos 'testValue'

Tento prístup dáva volajúcemu možnosť nastaviť alebo získať ľubovoľnú hodnotu v poli bez poskytnutia verejného prístupu k inak súkromnému $values samotné pole.

Bežná chyba č. 4: Dopytovanie v slučke

Nie je nezvyčajné naraziť na niečo také, ak váš PHP nefunguje:

$models = []; foreach ($inputValues as $inputValue) { $models[] = $valueRepository->findByValue($inputValue); }

Aj keď tu nemusí byť absolútne nič zlé, ale ak sa budete riadiť logikou v kóde, môžete zistiť, že nevinne vyzerajúci hovor hore na $valueRepository->findByValue() nakoniec vyústi do nejakého dotazu, napríklad:

$result = $connection->query('SELECT `x`,`y` FROM `values` WHERE `value`=' . $inputValue);

Výsledkom by bolo, že každá iterácia vyššie uvedenej slučky by mala za následok samostatný dopyt do databázy. Ak by ste napríklad do slučky zadali pole s 1 000 hodnotami, vygenerovalo by to 1 000 samostatných dotazov na zdroj! Ak sa takýto skript volá vo viacerých vláknach, mohlo by to systém potenciálne zastaviť.

Je preto kľúčové rozpoznať, kedy váš kód zadáva dotazy, a vždy, keď je to možné, zhromaždiť hodnoty a potom spustiť jeden dopyt, aby sa načítali všetky výsledky.

Jedným z príkladov pomerne bežného miesta, kde sa môžete stretnúť s neefektívnym uskutočňovaním dotazov (t. J. V slučke), je odoslanie formulára so zoznamom hodnôt (napríklad ID). Potom, aby sa získali úplné záznamové údaje pre každý z ID, bude kód prechádzať cez pole a robiť pre každý ID samostatný dotaz SQL. Často to bude vyzerať asi takto:

$data = []; foreach ($ids as $id) { $result = $connection->query('SELECT `x`, `y` FROM `values` WHERE `id` = ' . $id); $data[] = $result->fetch_row(); }

Ale to isté sa dá dosiahnuť oveľa efektívnejšie v a slobodný SQL dotaz takto:

$data = []; if (count($ids)) { $result = $connection->query('SELECT `x`, `y` FROM `values` WHERE `id` IN (' . implode(',', $ids)); while ($row = $result->fetch_row()) { $data[] = $row; } }

Je preto kľúčové rozpoznať, kedy sa váš kód priamo alebo nepriamo dotazuje. Kedykoľvek je to možné, zhromaždite hodnoty a potom spustite jeden dotaz, aby sa načítali všetky výsledky. Aj tu však musíme byť opatrní, čo nás vedie k našej ďalšej bežnej chybe PHP ...

Bežná chyba č. 5: Problémy a neefektívnosť využívania pamäte

Aj keď načítanie mnohých záznamov naraz je určite efektívnejšie ako spustenie jedného dotazu na načítanie každého riadku, takýto prístup môže potenciálne viesť k stavu „nedostatok pamäte“ v libmysqlclient pri použití PHP mysql predĺženie.

Na ukážku sa pozrime na testovaciu skrinku s obmedzenými zdrojmi (512 MB RAM), MySQL a php-cli.

Spustíme databázovú tabuľku takto:

// connect to mysql $connection = new mysqli('localhost', 'username', 'password', 'database'); // create table of 400 columns $query = 'CREATE TABLE `test`(`id` INT NOT NULL PRIMARY KEY AUTO_INCREMENT'; for ($col = 0; $col query($query); // write 2 million rows for ($row = 0; $row <2000000; $row++) { $query = 'INSERT INTO `test` VALUES ($row'; for ($col = 0; $col query($query); }

Dobre, poďme skontrolovať využitie zdrojov:

// connect to mysql $connection = new mysqli('localhost', 'username', 'password', 'database'); echo 'Before: ' . memory_get_peak_usage() . ' '; $res = $connection->query('SELECT `x`,`y` FROM `test` LIMIT 1'); echo 'Limit 1: ' . memory_get_peak_usage() . ' '; $res = $connection->query('SELECT `x`,`y` FROM `test` LIMIT 10000'); echo 'Limit 10000: ' . memory_get_peak_usage() . ' ';

Výkon:

Before: 224704 Limit 1: 224704 Limit 10000: 224704

V pohode Zdá sa, že dopyt je bezpečne riadený interne, čo sa týka zdrojov.

Pre istotu však ešte raz limit zvýšime a nastavíme ho na 100 000. Uh Oh. Keď to urobíme, dostaneme:

PHP Warning: mysqli::query(): (HY000/2013): Lost connection to MySQL server during query in /root/test.php on line 11

Čo sa stalo?

Problémom je spôsob, akým PHP mysql modul funguje. Je to skutočne iba proxy server libmysqlclient, ktorý vykonáva špinavú prácu. Keď je vybratá časť údajov, ide priamo do pamäte. Pretože táto pamäť nie je spravovaná správcom PHP, memory_get_peak_usage() nezvýši využitie zdrojov, keď v dotaze zvyšujeme limit. To vedie k problémom, ako je ten, ktorý sme demonštrovali vyššie, kde sme podvedení k uspokojeniu s domnienkou, že správa pamäte je v poriadku. Ale v skutočnosti je naša správa pamäte vážne chybná a môžeme naraziť na problémy, ako je ten, ktorý je uvedený vyššie.

Vyššej falošnej falošnej ukážke sa môžete vyhnúť (aj keď sama o sebe nezlepší využitie vašej pamäte) namiesto toho pomocou mysqlnd modul. mysqlnd je zostavený ako natívne rozšírenie PHP a to robí použite správcu pamäte PHP.

Preto, ak spustíme vyššie uvedený test pomocou mysqlnd namiesto mysql získame oveľa realistickejší obraz o využití pamäte:

Before: 232048 Limit 1: 324952 Limit 10000: 32572912

A mimochodom, je to ešte horšie. Podľa dokumentácie PHP, mysql používa dvakrát toľko zdrojov ako mysqlnd na ukladanie údajov, takže pôvodný skript pomocou mysql skutočne využilo ešte viac pamäte, ako je tu zobrazené (zhruba dvakrát toľko).

Ak sa chcete vyhnúť takýmto problémom, zvážte obmedzenie veľkosti svojich dotazov a použitie slučky s malým počtom iterácií; napr .:

$totalNumberToFetch = 10000; $portionSize = 100; for ($i = 0; $i query( 'SELECT `x`,`y` FROM `test` LIMIT $limitFrom, $portionSize'); }

Keď vezmeme do úvahy aj túto chybu PHP, aj chyba # 4 vyššie si uvedomujeme, že existuje zdravá rovnováha, ktorú váš kód v ideálnom prípade musí dosiahnuť medzi tým, že vaše dotazy budú príliš podrobné a opakujúce sa na jednej strane, a naopak, keď budú vaše jednotlivé dotazy príliš veľké. Rovnako ako vo väčšine vecí v živote, aj tu je potrebná rovnováha; buď extrém nie je dobrý a môže spôsobiť problémy s nesprávnym fungovaním PHP.

Bežná chyba č. 6: Ignorovanie problémov s kódmi Unicode / UTF-8

V istom zmysle je to skutočne viac problém samotného PHP ako niečoho, na čo by ste narazili pri ladení PHP, ale nikdy to nebolo adekvátne vyriešené. Jadro PHP 6 malo byť upravené na Unicode, ale to bolo pozastavené, keď bol vývoj PHP 6 pozastavený ešte v roku 2010.

To však vývojára v žiadnom prípade nezbavuje správne podáva UTF-8 a vyhnúť sa chybnému predpokladu, že všetky reťazce budú nevyhnutne „obyčajný starý ASCII“. Kód, ktorý nedokáže správne spracovať reťazce iné ako ASCII, je notoricky známy tým, že predstavuje gnarly heisenbugs do vášho kódu. Dokonca jednoduché strlen($_POST['name']) hovory by mohli spôsobiť problémy, ak by sa niekto s priezviskom ako „Schrödinger“ pokúsil prihlásiť do vášho systému.

Tu je malý kontrolný zoznam, aby ste sa vyhli problémom v kóde:

  • Ak neviete veľa o Unicode a UTF-8, mali by ste sa naučiť aspoň základné veci. Je tu skvelý základný náter tu .
  • Uistite sa, že vždy používate mb_* namiesto starých reťazcových funkcií (uistite sa, že je vo vašom zostavení PHP zahrnuté rozšírenie „multibyte“).
  • Uistite sa, že vaša databáza a tabuľky sú nastavené na použitie Unicode (mnoho zostáv MySQL stále štandardne používa latin1).
  • Pamätajte, že json_encode() prevádza symboly iné ako ASCII (napr. „Schrödinger“ sa stáva „Schr u00f6dinger“), ale serialize() robí nie .
  • Uistite sa, že vaše súbory s kódom PHP sú tiež kódované v UTF-8, aby ste sa vyhli kolíziám pri spájaní reťazcov s pevne zakódovanými alebo nakonfigurovanými konštantami reťazca.

Obzvlášť cenným zdrojom v tomto ohľade je UTF-8 Primer pre PHP a MySQL príspevok od Francisco Claria na tomto blogu.

Spoločná chyba č. 7: Za predpokladu $_POST bude vždy obsahovať vaše údaje POST

Napriek svojmu názvu sa $_POST pole nebude vždy obsahovať vaše údaje POST a dá sa ľahko nájsť prázdne. Aby sme tomu porozumeli, pozrime sa na príklad. Predpokladajme, že zadáme požiadavku na server pomocou jQuery.ajax() volať nasledovne:

// js $.ajax({ url: 'http://my.site/some/path', method: 'post', data: JSON.stringify({a: 'a', b: 'b'}), contentType: 'application/json' });

(Mimochodom, všimnite si contentType: 'application/json' tu. Údaje odosielame ako JSON, čo je pre API veľmi populárne. Je to predvolené nastavenie, napríklad pre zverejňovanie v AngularJS $http služby .)

Na strane servera nášho príkladu jednoducho vypíšeme $_POST pole:

// php var_dump($_POST);

Výsledkom bude prekvapivo:

array(0) { }

Prečo? Čo sa stalo s našim reťazcom JSON {a: 'a', b: 'b'}?

Odpoveď je taká PHP analyzuje užitočné zaťaženie POST automaticky iba vtedy, keď má typ obsahu application/x-www-form-urlencoded alebo multipart/form-data. Dôvody sú historické - tieto dva typy obsahu boli v podstate jediné, ktoré sa používali pred rokmi, keď PHP $_POST bol implementovaný. Takže pri akomkoľvek inom type obsahu (dokonca aj pri tých, ktoré sú dnes veľmi populárne, napríklad application/json), PHP automaticky nenačíta užitočné zaťaženie POST.

Od $_POST je superglobálny, ak ho prekonáme raz (najlepšie na začiatku nášho skriptu) bude upravená hodnota (t. j. vrátane užitočného zaťaženia POST) odkazovateľná v celom našom kóde. To je dôležité, pretože $_POST sa bežne používa v rámci PHP a takmer vo všetkých vlastných skriptoch na extrakciu a transformáciu údajov žiadosti.

Napríklad pri spracovaní užitočného zaťaženia POST s typom obsahu application/json musíme ručne analyzovať obsah požiadavky (t. J. Dekódovať údaje JSON) a prepísať $_POST premenná takto:

// php $_POST = json_decode(file_get_contents('php://input'), true);

Potom, keď vypíšeme $_POST pole, vidíme, že správne obsahuje užitočné zaťaženie POST; napr .:

array(2) { ['a']=> string(1) 'a' ['b']=> string(1) 'b' }

Bežná chyba č. 8: Myslenie, že PHP podporuje dátový typ znakov

Pozrite sa na túto ukážku kódu a skúste hádať, čo sa bude tlačiť:

for ($c = 'a'; $c <= 'z'; $c++) { echo $c . ' '; }

Ak ste odpovedali „a“ až „z“, možno vás prekvapí, že ste sa mýlili.

Áno, bude tlačiť „a“ až „z“, ale potom bude tiež tlačte „aa“ až „yz“. Pozrime sa prečo.

V PHP neexistujú char Dátový typ; iba string je k dispozícii. Z tohto dôvodu zvyšujeme string z vo výťažkoch PHP aa:

php> $c = 'z'; echo ++$c . ' '; aa

Napriek tomu veci ešte viac zamieňajú, aa je lexikograficky menej než z:

php> var_export((boolean)('aa' <'z')) . ' '; true

Preto vyššie uvedený vzorový kód vytlačí písmená a až z, ale potom tiež výtlačky aa prostredníctvom yz. Zastaví sa, keď dosiahne za, čo je prvá hodnota, ktorú zaznamená, že je „väčšia ako“ z:

php> var_export((boolean)('za' <'z')) . ' '; false

V takom prípade existuje jeden spôsob, ako správne slučka medzi hodnotami „a“ až „z“ v PHP:

for ($i = ord('a'); $i <= ord('z'); $i++) { echo chr($i) . ' '; }

Alebo alternatívne:

$letters = range('a', 'z'); for ($i = 0; $i

Bežná chyba č. 9: Ignorovanie štandardov kódovania

Aj keď ignorovanie štandardov kódovania priamo nevedie k nutnosti ladenia kódu PHP, stále je to pravdepodobne jedna z najdôležitejších vecí, o ktorej sa tu bude diskutovať.

Ignorovanie štandardov kódovania môže spôsobiť v projekte celý rad problémov. V lepšom prípade to vedie k nekonzistentnému kódu (pretože každý vývojár si „robí svoje veci“). Ale v najhoršom prípade produkuje kód PHP, ktorý nefunguje alebo ktorého navigácia je zložitá (niekedy takmer nemožná), takže je nesmierne ťažké ho odladiť, vylepšiť alebo udržiavať. A to znamená zníženie produktivity vášho tímu vrátane množstva zbytočného (alebo prinajmenšom zbytočného) úsilia.

Našťastie pre vývojárov PHP existuje odporúčanie štandardov PHP (PSR), ktoré obsahuje týchto päť štandardov:

  • PSR-0 : Automatické načítanie štandard
  • PSR-1 : Základný štandard kódovania
  • PSR-2 : Sprievodca štýlom kódovania
  • PSR-3 : Logger Interface
  • PSR-4 : Autoloader

PSR bolo pôvodne vytvorené na základe vstupov od správcov najuznávanejších platforiem na trhu. Zend, Drupal, Symfony, Joomla a iné prispeli k týmto štandardom a v súčasnosti sa nimi riadia. Dokonca aj PEAR, ktorý sa roky predtým snažil byť štandardom, sa teraz zúčastňuje PSR.

V istom zmysle takmer nezáleží na tom, aký je váš štandard kódovania, pokiaľ sa na norme dohodnete a budete sa jej držať, ale dodržiavanie PSR je všeobecne dobrý nápad, pokiaľ nemáte na svojom projekte nejaký pádny dôvod, prečo by ste mali postupovať inak . Stále viac tímov a projektov je v súlade s PSR. Spoločnosť Tt je v tomto okamihu jednoznačne uznaná ako „štandard“ väčšiny vývojárov PHP, takže jej použitie pomôže zabezpečiť, aby noví vývojári boli oboznámení a vyhovovali vášmu štandardu kódovania, keď sa stanú členom vášho tímu.

Bežná chyba č. 10: Zneužitie empty()

Niektorí vývojári PHP radi používajú empty() na boolovské šeky takmer na všetko. Existujú prípady, keď to môže viesť k zámene.

Najskôr sa vráťme k poliam a ArrayObject inštancie (ktoré napodobňujú polia). Vzhľadom na ich podobnosť je ľahké predpokladať, že polia a ArrayObject inštancie sa budú správať identicky. To sa však ukazuje ako nebezpečný predpoklad. Napríklad v PHP 5.0:

// PHP 5.0 or later: $array = []; var_dump(empty($array)); // outputs bool(true) $array = new ArrayObject(); var_dump(empty($array)); // outputs bool(false) // why don't these both produce the same output?

A aby toho nebolo málo, výsledky by boli pred PHP 5.0 odlišné:

// Prior to PHP 5.0: $array = []; var_dump(empty($array)); // outputs bool(false) $array = new ArrayObject(); var_dump(empty($array)); // outputs bool(false)

Tento prístup je bohužiaľ dosť populárny. Napríklad toto je cesta ZendDbTableGateway of Zend Framework 2 returns data when calling current() dňa TableGateway::select() výsledok, ako navrhuje doktor. S takýmito údajmi sa vývojár môže ľahko stať obeťou tejto chyby.

Ak sa chcete vyhnúť týmto problémom, lepším prístupom ku kontrole štruktúr prázdneho poľa je použitie count():

// Note that this work in ALL versions of PHP (both pre and post 5.0): $array = []; var_dump(count($array)); // outputs int(0) $array = new ArrayObject(); var_dump(count($array)); // outputs int(0)

A mimochodom, keďže PHP odovzdáva 0 do false, count() možno použiť aj v rámci if () podmienky na kontrolu prázdnych polí. Za zmienku tiež stojí, že v PHP count() je konštantná zložitosť (O(1) prevádzka) na poliach, čo ešte viac objasňuje, že je to správna voľba.

Ďalším príkladom, keď empty() môže byť nebezpečné, keď ho skombinujete s funkciou magickej triedy __get(). Poďme definovať dve triedy a mať test majetok v oboch.

Najprv si zadefinujeme Regular trieda, ktorá obsahuje test ako bežná vlastnosť:

komu podáva správu CFO
class Regular { public $test = 'value'; }

Potom definujme Magic trieda, ktorá používa kúzlo __get() operátorovi prístup k jeho test nehnuteľnosť:

class Magic { private $values = ['test' => 'value']; public function __get($key) { if (isset($this->values[$key])) { return $this->values[$key]; } } }

Dobre, pozrime sa, čo sa stane, keď sa pokúsime získať prístup k test majetok každej z týchto tried:

$regular = new Regular(); var_dump($regular->test); // outputs string(4) 'value' $magic = new Magic(); var_dump($magic->test); // outputs string(4) 'value'

Zatiaľ v poriadku.

Teraz sa však pozrime, čo sa stane, keď zavoláme empty() na každom z nich:

var_dump(empty($regular->test)); // outputs bool(false) var_dump(empty($magic->test)); // outputs bool(true)

Uf. Ak sa teda spoliehame na empty(), môžeme byť mylne presvedčení, že test majetok $magic je prázdny, zatiaľ čo v skutočnosti je nastavený na 'value'.

Bohužiaľ, ak trieda používa kúzlo __get() funkcia na získanie hodnoty vlastnosti, neexistuje spoľahlivý spôsob, ako skontrolovať, či je hodnota vlastnosti prázdna alebo nie. Mimo rozsahu triedy môžete skontrolovať iba to, či null hodnota sa vráti a to nevyhnutne neznamená, že nie je nastavený zodpovedajúci kľúč, pretože v skutočnosti je mohol bol nastaviť do null.

Naopak, ak sa pokúsime odkazovať na neexistujúcu vlastnosť a Regular inštancie triedy, dostaneme oznámenie podobné tomuto:

Notice: Undefined property: Regular::$nonExistantTest in /path/to/test.php on line 10 Call Stack: 0.0012 234704 1. {main}() /path/to/test.php:0

Hlavným bodom je teda to, že empty() Táto metóda by sa mala používať opatrne, pretože môže spôsobiť mätúce - alebo dokonca potenciálne zavádzajúce - výsledky, ak nie je opatrný.

Zabaliť

Ľahké použitie PHP môže vývojárov priviesť k falošnému pocitu pohodlia, vďaka čomu môžu zostať zraniteľní voči zdĺhavému ladeniu PHP kvôli niektorým nuansám a zvláštnostiam jazyka. To môže mať za následok nefunkčnosť PHP a problémy, ako sú tie, ktoré sú tu opísané.

Jazyk PHP sa počas svojej 20-ročnej histórie významne vyvinul. Oboznámiť sa s jeho jemnosťami je užitočné úsilie, pretože pomôže zabezpečiť, aby softvér, ktorý vyrábate je škálovateľnejšia, robustnejšia a udržiavateľnejšia.

Úvod do spracovania obrazu v jazyku Python vo výpočtovej fotografii

Technológie

Úvod do spracovania obrazu v jazyku Python vo výpočtovej fotografii
Značky sú stále dôležité - bezvýznamný rozmach

Značky sú stále dôležité - bezvýznamný rozmach

Dizajn Ux

Populárne Príspevky
Augmented Reality vs. Virtual Reality vs. Mixed Reality - Úvodný sprievodca
Augmented Reality vs. Virtual Reality vs. Mixed Reality - Úvodný sprievodca
Správa: Stav pracovných síl
Správa: Stav pracovných síl
Päť techník vyskúšaných v bitke, ktoré váš vývojár rozhrania WordPress API nepoužíva
Päť techník vyskúšaných v bitke, ktoré váš vývojár rozhrania WordPress API nepoužíva
Prvé dojmy - Sprievodca prihlásením sa do UX
Prvé dojmy - Sprievodca prihlásením sa do UX
Prispôsobia sa nakupujúci a vývojári marketingu v blízkosti obchodu v obchode?
Prispôsobia sa nakupujúci a vývojári marketingu v blízkosti obchodu v obchode?
 
Electron: Desktopové aplikácie pre rôzne platformy sú jednoduché
Electron: Desktopové aplikácie pre rôzne platformy sú jednoduché
Don't Hate WordPress: 5 Common Biases Debunked
Don't Hate WordPress: 5 Common Biases Debunked
Sass Mixins: Udržujte svoje štýly suché
Sass Mixins: Udržujte svoje štýly suché
REST zaistené vs. JMeter: Porovnanie nástrojov na testovanie REST
REST zaistené vs. JMeter: Porovnanie nástrojov na testovanie REST
Vplyv s dizajnom - Sprievodca farbami a emóciami
Vplyv s dizajnom - Sprievodca farbami a emóciami
Populárne Príspevky
  • získať a transformovať (dotaz na silu)
  • ako urobiť telegram bot
  • techniky optimalizácie dotazov na serveri SQL
  • koľko je tam tokenov erc20
  • ako získať číslo kreditnej karty niekoho online
  • ako vytvoriť účtovnú osnovu
  • účtovná osnova pre výrobný podnik
Kategórie
  • Životný Cyklus Produktu
  • Iné
  • Agilný Talent
  • Projektový Manažment
  • © 2022 | Všetky Práva Vyhradené

    portaldacalheta.pt