portaldacalheta.pt
  • Основен
  • Kpi И Анализ
  • Инвеститори И Финансиране
  • Други
  • Финансови Процеси
Технология

Бъги PHP код: 10-те най-често срещани грешки, които PHP разработчиците правят



PHP улеснява сравнително лесното изграждане на уеб базирана система, което е голяма част от причината за нейната популярност. Но независимо от лекотата на използване, PHP се превърна в доста усъвършенстван език с много рамки, нюанси и тънкости, които могат да ухапят разработчиците, което води до часове отстраняване на грешки за издърпване на косата. Тази статия подчертава десет от най-често срещаните грешки, които PHP разработчици трябва да се пазите от.

Често срещана грешка # 1: Оставяне на висящи препратки към масива след foreach цикли

Не сте сигурни как да използвате цикли foreach в PHP? Използване на препратки в foreach цикли могат да бъдат полезни, ако искате да оперирате всеки елемент в масива, който итерирате. Например:



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

Проблемът е, че ако не внимавате, това може да има и нежелани странични ефекти и последици. По-конкретно, в горния пример, след изпълнението на кода, $value ще остане в обхвата и ще съдържа препратка към последния елемент в масива. Последващи операции, включващи $value следователно може непреднамерено да модифицира последния елемент в масива.



Основното нещо, което трябва да запомните е, че foreach не създава обхват. По този начин, $value в горния пример е a справка в горния обхват на скрипта. На всяка итерация foreach задава препратката към точка към следващия елемент на $array. Следователно след завършване на цикъла $value все още сочи към последния елемент на $array и остава в обхвата.



Ето пример за вида укриващи се и объркващи грешки, до които това може да доведе:

$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), ' ';

Горният код ще изведе следното:



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

Не, това не е печатна грешка. Последната стойност на последния ред наистина е 2, а не 3.

Защо?



След преминаване през първия foreach цикъл, $array остава непроменена, но, както е обяснено по-горе, $value е оставена като висяща препратка към последния елемент в $array (тъй като този foreach цикъл е достъпен $value от справка ).

каква е втората стъпка от капиталовото бюджетиране?

В резултат на това, когато преминем през втория foreach цикъл, изглежда, че се случват „странни неща“. По-конкретно, тъй като $value сега е достъпен по стойност (т.е. чрез копие ), foreach копия всяка последователна $array елемент в $value във всяка стъпка от цикъла. В резултат ето какво се случва по време на всяка стъпка от втората foreach цикъл:



  • Пропуск 1: Копия $array[0] (т.е. „1“) в $value (което е препратка към $array[2]), така че $array[2] сега е равно на 1. Значи $array сега съдържа [1, 2, 1].
  • Пропуск 2: Копия $array[1] (т.е. „2“) в $value (което е препратка към $array[2]), така че $array[2] сега е равно на 2. Значи $array сега съдържа [1, 2, 2].
  • Пропуск 3: Копия $array[2] (което сега е равно на „2“) в $value (което е препратка към $array[2]), така че $array[2] все още е равно на 2. Така че $array сега съдържа [1, 2, 2].

За да продължите да се възползвате от използването на референции в foreach цикли, без да рискувате от този вид проблеми, извикайте unset() върху променливата, веднага след foreach цикъл, за да премахнете препратката; напр .:

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

Често срещана грешка # 2: Неразбиране isset() поведение

Въпреки името си, isset() не само връща false, ако елемент не съществува, но също връща false за null стойности .



Това поведение е по-проблематично, отколкото може да изглежда в началото и е често срещан източник на проблеми.

Помислете за следното:



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

Авторът на този код вероятно е искал да провери дали keyShouldBeSet бе зададено в $data. Но, както беше обсъдено, isset($data['keyShouldBeSet']) ще също връщане на false, ако $data['keyShouldBeSet'] беше зададен, но е зададен на null. Така че горната логика е погрешна.

Ето още един пример:

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

Горният код предполага, че ако $_POST['active'] връща true, след това postData задължително ще бъде зададено и следователно isset($postData) ще се върне true. И обратно, горният код приема, че само по този начин isset($postData) ще се върне false е ако $_POST['active'] върнати false както добре.

Не.

Както беше обяснено, isset($postData) също ще върне false ако $postData бе зададено на null. Ето защо е възможно за isset($postData) за връщане false дори ако $_POST['active'] върнати true. И така, горната логика е погрешна.

И между другото, като странична точка, ако целта в горния код наистина е била отново да провери дали $_POST['active'] върна вярно, разчитайки на isset() тъй като това беше лошо решение за кодиране във всеки случай. Вместо това би било по-добре просто да проверите отново $_POST['active']; т.е.:

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

За случаите обаче къде е важно е да се провери дали дадена променлива наистина е зададена (т.е., за да се прави разлика между променлива, която не е зададена, и променлива, която е зададена на null), array_key_exists() метод е много по-стабилно решение.

Например, можем да пренапишем първия от горните два примера, както следва:

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

Освен това, чрез комбиниране array_key_exists() с get_defined_vars() , можем надеждно да проверим дали променлива в текущия обхват е зададена или не:

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

Често срещана грешка # 3: Объркване относно връщането по препратка спрямо стойност

Помислете за този кодов фрагмент:

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

Ако изпълните горния код, ще получите следното:

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

Какво не е наред?

Проблемът е, че горният код обърква връщащите масиви чрез препратка към връщащите масиви по стойност. Освен ако изрично не кажете на PHP да върне масив чрез препратка (т.е. с помощта на &), PHP по подразбиране ще върне масива 'по стойност'. Това означава, че a копие на масива ще бъде върнат и следователно извиканата функция и повикващият няма да имат достъп до същия екземпляр на масива.

Така че горното обаждане до getValues() връща a копие от $values масив, а не препратка към него. Имайки това предвид, нека преразгледаме двата ключови реда от горния пример:

// 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'];

Една възможна корекция би била запазването на първото копие на $values масив, върнат от getValues() и след това да оперира с това копие впоследствие; напр .:

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

Този код ще работи добре (т.е. ще изведе test, без да генерира съобщение с „недефиниран индекс“), но в зависимост от това, което се опитвате да постигнете, този подход може или не може да бъде адекватен. По-специално, горният код няма да промени оригинала $values масив. Така че, ако вие направете искате вашите модификации (като добавяне на елемент „test“) да повлияят на оригиналния масив, вместо това ще трябва да промените getValues() функция за връщане на a справка към $values самия масив. Това става чрез добавяне на & преди името на функцията, като по този начин показва, че тя трябва да върне препратка; т.е.:

на какъв език са написани дискорд ботовете
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'];

Резултатът от това ще бъде test, както се очаква.

Но за да направите нещата по-объркващи, помислете вместо това за следния кодов фрагмент:

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'];

Ако се досещате, че това би довело до същата грешка „недефиниран индекс“ като нашата по-рано array например, сгрешихте. Всъщност, това кодът ще работи добре. Причината е, че за разлика от масивите, PHP винаги предава обекти по препратка . (ArrayObject е SPL обект, който напълно имитира използването на масиви, но работи като обект.)

Както показват тези примери, не винаги е напълно очевидно в PHP дали имате работа с копие или препратка. Следователно е от съществено значение да се разберат тези поведения по подразбиране (т.е. променливите и масивите се предават по стойност; обектите се предават по препратка) и също така внимателно да се провери документацията на API за функцията, която извиквате, за да видите дали връща стойност, a копие на масив, препратка към масив или препратка към обект.

Всичко казано, важно е да се отбележи, че практиката на връщане на препратка към масив или ArrayObject обикновено е нещо, което трябва да се избягва, тъй като предоставя на повикващия възможността да променя личните данни на инстанцията. Това „лети в лицето” на капсулирането. Вместо това е по-добре да използвате „гетери“ и „сетери“ от стар стил, напр .:

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'

Този подход дава възможност на повикващия да зададе или да получи каквато и да е стойност в масива, без да предоставя публичен достъп до иначе частния $values самия масив.

Често срещана грешка # 4: Извършване на заявки в цикъл

Не е необичайно да попаднете на нещо подобно, ако вашият PHP не работи:

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

Макар че тук може да няма абсолютно нищо лошо, но ако следвате логиката в кода, може да откриете, че невинно изглеждащият призив по-горе да $valueRepository->findByValue() в крайна сметка води до някаква заявка, като например:

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

В резултат на това всяка итерация на горния цикъл ще доведе до отделна заявка към базата данни. Така че, ако например сте предоставили масив от 1000 стойности на цикъла, той ще генерира 1000 отделни заявки към ресурса! Ако такъв скрипт бъде извикан в множество нишки, той потенциално може да спре системата да се спре.

Следователно е от решаващо значение да разпознаете кога се правят заявки от вашия код и, когато е възможно, да събирате стойностите и след това да стартирате една заявка, за да извлечете всички резултати.

Един пример за доста често срещано място за среща с заявки, които се извършват неефективно (т.е. в цикъл), е когато формуляр се публикува със списък със стойности (идентификатори например). След това, за да се извлекат пълните данни за запис за всеки от идентификаторите, кодът ще премине през масива и ще направи отделна SQL заявка за всеки идентификатор. Това често изглежда по следния начин:

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

Но едно и също нещо може да бъде постигнато много по-ефективно в a неженен SQL заявка, както следва:

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

Следователно е от решаващо значение да разпознаете кога се правят заявки, пряко или косвено, от вашия код. Когато е възможно, съберете стойностите и след това изпълнете една заявка, за да извлечете всички резултати. И все пак там трябва да се внимава, което ни води до следващата ни често срещана грешка в PHP ...

Често срещана грешка # 5: Използване на паметта headfakes и неефективност

Въпреки че извличането на много записи наведнъж е определено по-ефективно от изпълнението на една заявка за всеки ред за извличане, такъв подход може потенциално да доведе до състояние на „липса на памет“ в libmysqlclient при използване на PHP mysql удължаване.

За да демонстрираме, нека да разгледаме тестово поле с ограничени ресурси (512MB RAM), MySQL и php-cli

Ще заредим таблица на база данни като тази:

// 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); }

Добре, сега да проверим използването на ресурси:

// 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() . ' ';

Изход:

Before: 224704 Limit 1: 224704 Limit 10000: 224704

Готино. Изглежда, че заявката се управлява безопасно вътрешно по отношение на ресурсите.

Само за да сме сигурни, нека увеличим лимита още веднъж и да го зададем на 100 000. А-а. Когато правим това, получаваме:

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

Какво стана?

Въпросът тук е в начина, по който PHP | | + + _ | модул работи. Това всъщност е само прокси за mysql, което върши мръсната работа. Когато е избрана част от данните, тя отива директно в паметта. Тъй като тази памет не се управлява от мениджъра на PHP, libmysqlclient няма да покаже никакво увеличение на използването на ресурси, тъй като увеличаваме ограничението в заявката си. Това води до проблеми като този, демонстриран по-горе, при които ни подвеждат да се самоуспокояваме, мислейки, че управлението на паметта ни е наред. Но в действителност управлението на паметта ни е сериозно недостатъчно и можем да изпитаме проблеми като този, показан по-горе.

Можете поне да избегнете горепосочената глава (въпреки че тя сама по себе си няма да подобри използването на паметта), като вместо това използвате memory_get_peak_usage() модул. mysqlnd се компилира като естествено PHP разширение и то прави използвайте мениджъра на паметта на PHP.

Следователно, ако изпълним горния тест, използвайки mysqlnd вместо mysqlnd, получаваме много по-реалистична картина на използването на паметта ни:

mysql

И между другото е дори по-лошо от това. Според PHP документацията, Before: 232048 Limit 1: 324952 Limit 10000: 32572912 използва два пъти повече ресурси от mysql за съхраняване на данни, така че оригиналният скрипт използва mysqlnd наистина използва дори повече памет, отколкото е показана тук (приблизително два пъти повече).

За да избегнете подобни проблеми, помислете за ограничаване на размера на вашите заявки и използване на цикъл с малък брой итерации; напр .:

mysql

Когато разгледаме и тази грешка в PHP и грешка # 4 по-горе, ние осъзнаваме, че има здравословен баланс, който вашият код в идеалния случай трябва да постигне между това, от една страна, да имате твърде подробни и повтарящи се запитвания, срещу това, че всяка ваша индивидуална заявка е твърде голяма. Както е вярно с повечето неща в живота, необходим е баланс; и двете крайности не са добри и могат да причинят проблеми с PHP, който не работи правилно.

Често срещана грешка # 6: Игнориране на Unicode / UTF-8 проблеми

В известен смисъл това наистина е по-скоро проблем в самия PHP, отколкото нещо, с което бихте се сблъскали при отстраняване на грешки в PHP, но никога не е било адресирано адекватно. Ядрото на PHP 6 трябваше да бъде осъзнато от Unicode, но това беше спряно, когато разработването на PHP 6 беше спряно през 2010 г.

Но това в никакъв случай не освобождава разработчика от правилно предаване на UTF-8 и избягване на погрешното предположение, че всички низове непременно ще бъдат „обикновен стар ASCII“. Кодът, който не се справя правилно с низове, различни от ASCII, е известен с въвеждането на gnarly heisenbugs във вашия код. Дори просто $totalNumberToFetch = 10000; $portionSize = 100; for ($i = 0; $i query( 'SELECT `x`,`y` FROM `test` LIMIT $limitFrom, $portionSize'); } обажданията могат да създадат проблеми, ако някой с фамилно име като „Schrödinger“ се опита да влезе във вашата система.

Ето малък контролен списък, за да избегнете подобни проблеми във вашия код:

  • Ако не знаете много за Unicode и UTF-8, трябва поне да научите основите. Има страхотен буквар тук .
  • Уверете се, че винаги използвате strlen($_POST['name']) функции вместо старите низови функции (уверете се, че разширението “multibyte” е включено във вашата PHP компилация).
  • Уверете се, че вашата база данни и таблици са настроени да използват Unicode (много компилации на MySQL все още използват mb_* по подразбиране).
  • Не забравяйте, че latin1 преобразува символи, които не са ASCII (напр. „Schrödinger“ става „Schr u00f6dinger“), но json_encode() прави не .
  • Уверете се, че вашите PHP кодови файлове също са кодирани UTF-8, за да се избегнат сблъсъци при обединяване на низове с твърдо кодирани или конфигурирани константи на низове.

Особено ценен ресурс в това отношение е UTF-8 Primer за PHP и MySQL публикувано от Франсиско Клария в този блог.

Често срещана грешка # 7: Ако приемем serialize() винаги ще съдържа вашите POST данни

Въпреки името си, $_POST array не винаги ще съдържа вашите POST данни и може лесно да се намери празен. За да разберем това, нека разгледаме един пример. Да приемем, че правим заявка за сървър с $_POST обадете се както следва:

jQuery.ajax()

(Между другото, обърнете внимание на // js $.ajax({ url: 'http://my.site/some/path', method: 'post', data: JSON.stringify({a: 'a', b: 'b'}), contentType: 'application/json' }); тук. Изпращаме данни като JSON, което е доста популярно за API. Това е по подразбиране, например, за публикуване в AngularJS contentType: 'application/json' обслужване .)

От страна на сървъра на нашия пример просто изхвърляме $http масив:

$_POST

Изненадващо, резултатът ще бъде:

// php var_dump($_POST);

Защо? Какво се случи с нашия JSON низ array(0) { }

какво измерва ценовата еластичност на търсенето

Отговорът е такъв PHP анализира POST полезен товар автоматично само когато има тип съдържание {a: 'a', b: 'b'} или application/x-www-form-urlencoded. Причините за това са исторически - тези два типа съдържание по същество бяха единствените, използвани преди години, когато PHP’s multipart/form-data е изпълнен. Така че с всеки друг тип съдържание (дори с тези, които са доста популярни днес, като $_POST), PHP не зарежда автоматично полезния товар на POST.

Тъй като application/json е суперглобален, ако го заменим веднъж (за предпочитане в началото на нашия скрипт), модифицираната стойност (т.е., включително полезния товар на POST) ще бъде референтна в целия ни код. Това е важно, тъй като $_POST се използва често от PHP рамки и почти всички персонализирани скриптове за извличане и трансформиране на данни за заявки.

Така например, когато обработваме POST полезен товар с тип съдържание $_POST, трябва ръчно да анализираме съдържанието на заявката (т.е. да декодираме JSON данните) и да заменим application/json променлива, както следва:

$_POST

Тогава, когато изхвърляме // php $_POST = json_decode(file_get_contents('php://input'), true); масив, виждаме, че той правилно включва полезния товар на POST; напр .:

$_POST

Често срещана грешка # 8: Мисленето, че PHP поддържа тип данни за символи

Погледнете тази примерна част от кода и опитайте да познаете какво ще отпечата:

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

Ако сте отговорили с „а“ до „z“, може да се изненадате да разберете, че сте сгрешили.

Да, ще отпечата „а“ до „z“, но след това ще го направи също отпечатайте „aa“ през „yz“. Нека да видим защо.

В PHP няма for ($c = 'a'; $c <= 'z'; $c++) { echo $c . ' '; } тип данни; само char е на разположение. Имайки това предвид, увеличаване на string string в PHP добиви z:

aa

И все пак, за да объркаме нещата, php> $c = 'z'; echo ++$c . ' '; aa е лексикографски по-малко от aa:

z

Ето защо примерният код, представен по-горе, отпечатва буквите php> var_export((boolean)('aa' <'z')) . ' '; true през a, но след това също разпечатки z през aa. Спира, когато достигне yz, което е първата стойност, която среща, че е 'по-голяма от' za:

z

В този случай ето един от начините да правилно цикъл през стойностите от 'а' до 'z' в PHP:

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

Или алтернативно:

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

Често срещана грешка # 9: Пренебрегване на стандартите за кодиране

Въпреки че игнорирането на стандартите за кодиране не води пряко до необходимостта от отстраняване на грешки в PHP кода, това все още е може би едно от най-важните неща за обсъждане тук.

Пренебрегването на стандартите за кодиране може да доведе до множество проблеми в проекта. В най-добрия резултат се получава код, който е непоследователен (тъй като всеки разработчик „прави своето нещо“). Но в най-лошия случай той произвежда PHP код, който не работи или може да бъде труден (понякога почти невъзможен) за навигация, което прави изключително трудно отстраняването на грешки, подобряването, поддържането. А това означава намалена производителност на вашия екип, включително много загубени (или поне ненужни) усилия.

За щастие на разработчиците на PHP има препоръка за стандарти за PHP (PSR), състояща се от следните пет стандарта:

  • PSR-0 : Стандарт за автоматично зареждане
  • PSR-1 : Основен стандарт за кодиране
  • PSR-2 : Ръководство за стил на кодиране
  • PSR-3 : Интерфейс на регистратора
  • PSR-4 : Autoloader

PSR първоначално е създаден въз основа на данни от поддръжници на най-признатите платформи на пазара. Zend, Drupal, Symfony, Joomla и други допринесоха за тези стандарти и сега ги спазват. Дори PEAR, който се опита да бъде стандарт в продължение на години преди това, участва в PSR сега.

В някакъв смисъл почти няма значение какъв е вашият стандарт за кодиране, стига да се съгласите за стандарт и да се придържате към него, но спазването на PSR обикновено е добра идея, освен ако нямате убедителна причина в проекта си да правите друго . Все повече и повече екипи и проекти са в съответствие с PSR. Tt определено е признат на този етап като „стандарт“ от повечето разработчици на PHP, така че използването му ще помогне да се гарантира, че новите разработчици са запознати и се чувстват комфортно с вашия стандарт за кодиране, когато се присъединят към вашия екип.

Често срещана грешка # 10: Злоупотреба $letters = range('a', 'z'); for ($i = 0; $i

Някои разработчици на PHP обичат да използват empty() за булеви проверки за почти всичко. Има случаи обаче, когато това може да доведе до объркване.

Първо, нека се върнем към масивите и empty() екземпляри (които имитират масиви). Предвид тяхната прилика е лесно да се приеме, че масивите и ArrayObject екземплярите ще се държат идентично. Това обаче се оказва опасно предположение. Например в PHP 5.0:

ArrayObject

И за да направим нещата още по-лоши, резултатите биха били различни преди 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?

За съжаление този подход е доста популярен. Например това е начинът // Prior to PHP 5.0: $array = []; var_dump(empty($array)); // outputs bool(false) $array = new ArrayObject(); var_dump(empty($array)); // outputs bool(false) на Zend Framework 2 връща данни при извикване ZendDbTableGateway на current() резултат, както предлага документът. Разработчикът може лесно да стане жертва на тази грешка с такива данни.

За да се избегнат тези проблеми, по-добрият подход за проверка на празни масивни структури е да се използва TableGateway::select():

count()

И между другото, тъй като PHP хвърля // 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) до 0, false може да се използва и в рамките на count() условия за проверка на празни масиви. Също така си струва да се отбележи, че в PHP, if () е постоянна сложност (count() операция) върху масиви, което прави още по-ясно, че това е правилният избор.

Друг пример, когато O(1) може да бъде опасно, когато го комбинирате с функцията магически клас empty() Нека дефинираме два класа и имаме __get() собственост и в двете.

Първо нека дефинираме test клас, който включва Regular като нормално свойство:

test

Тогава нека дефинираме class Regular { public $test = 'value'; } клас, който използва магията Magic оператор за достъп до неговия __get() Имот:

test

Добре, сега да видим какво се случва, когато се опитаме да получим достъп до class Magic { private $values = ['test' => 'value']; public function __get($key) { if (isset($this->values[$key])) { return $this->values[$key]; } } } свойство на всеки от тези класове:

test

Засега глоба.

Но сега да видим какво се случва, когато се обадим $regular = new Regular(); var_dump($regular->test); // outputs string(4) 'value' $magic = new Magic(); var_dump($magic->test); // outputs string(4) 'value' на всеки от тях:

empty()

Ъъъ. Така че, ако разчитаме на var_dump(empty($regular->test)); // outputs bool(false) var_dump(empty($magic->test)); // outputs bool(true) , можем да бъдем подведени да вярваме, че empty() собственост на test е празно, докато в действителност е зададено на $magic.

За съжаление, ако клас използва магията 'value' функция за извличане на стойност на свойство, няма надежден начин да проверите дали стойността на това свойство е празна или не. Извън обхвата на класа наистина можете да проверите само дали __get() стойност ще бъде върната и това не означава непременно, че съответният ключ не е зададен, тъй като всъщност е бих могъл бил е комплект до null.

изобразяване от страна на клиента срещу изобразяване от страна на сървъра

За разлика от това, ако се опитаме да се позовем на несъществуващо свойство на null екземпляр на клас, ще получим известие, подобно на следното:

Regular

Така че основната точка тук е, че 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 методът трябва да се използва внимателно, тъй като може да доведе до объркващи - или дори потенциално подвеждащи - резултати, ако човек не е внимателен.

Обобщение

Лесната употреба на PHP може да приспи разработчиците във фалшиво чувство за комфорт, оставяйки себе си уязвими за продължително отстраняване на грешки в PHP поради някои нюанси и особености на езика. Това може да доведе до неработене на PHP и проблеми като описаните тук.

Езикът PHP се е развил значително през своята 20-годишна история. Запознаването с неговите тънкости е полезно начинание, тъй като ще помогне да се гарантира, че софтуер, който произвеждате е по-мащабируема, здрава и поддържаема.

Линии на комуникация - История на шрифта (с инфографика)

Ui Design

Линии на комуникация - История на шрифта (с инфографика)
Олово за технологична практика

Олово за технологична практика

Други

Популярни Публикации
Първи стъпки с модули и модулна разработка отпред
Първи стъпки с модули и модулна разработка отпред
Най-добри практики за уеб оформление: Анализирани са 12 вечни модела на потребителския интерфейс
Най-добри практики за уеб оформление: Анализирани са 12 вечни модела на потребителския интерфейс
H-1B: Пътешествие на разработчика на iOS от Хондурас до Силициевата долина
H-1B: Пътешествие на разработчика на iOS от Хондурас до Силициевата долина
Agile UX: Как да включите UX и продуктовия дизайн в Agile
Agile UX: Как да включите UX и продуктовия дизайн в Agile
Съвети за привличане, управление и задържане на разработчици на софтуер
Съвети за привличане, управление и задържане на разработчици на софтуер
 
Въведение в търговията с дълбоко обучение в хедж фондове
Въведение в търговията с дълбоко обучение в хедж фондове
Magento 2: Ревизия или революция?
Magento 2: Ревизия или революция?
Кутия с инструменти на Forecaster’s: Как да извършите симулации на Монте Карло
Кутия с инструменти на Forecaster’s: Как да извършите симулации на Монте Карло
Ръководител на растежа
Ръководител на растежа
Вицепрезидент по комуникациите
Вицепрезидент по комуникациите
Популярни Публикации
  • включително какво, изкривява ефективността на изобразяването на точки от данни?
  • addconnectioncallbacks в конструктора не може да се приложи
  • принципи на дефиниране на проектния баланс
  • addconnectioncallbacks в конструктора не може да се приложи
  • безплатна хакната информация за кредитна карта
  • коя програма грабва потребителски файлове от система, за да можете да ги мигрирате на друг компютър?
Категории
  • Kpi И Анализ
  • Инвеститори И Финансиране
  • Други
  • Финансови Процеси
  • © 2022 | Всички Права Запазени

    portaldacalheta.pt