久久福利_99r_国产日韩在线视频_直接看av的网站_中文欧美日韩_久久一

您的位置:首頁技術(shù)文章
文章詳情頁

十個PHP開發(fā)者最容易犯的錯誤

瀏覽:158日期:2022-09-11 14:25:42

PHP 語言讓 WEB 端程序設(shè)計變得簡單,這也是它能流行起來的原因。但也是因為它的簡單,PHP 也慢慢發(fā)展成一個相對復(fù)雜的語言,層出不窮的框架,各種語言特性和版本差異都時常讓搞的我們頭大,不得不浪費大量時間去調(diào)試。這篇文章列出了十個最容易出錯的地方,值得我們?nèi)プ⒁狻?/p>

十個PHP開發(fā)者最容易犯的錯誤

 易犯錯誤 #1: 在 foreach循環(huán)后留下數(shù)組的引用

還不清楚 PHP 中 foreach 遍歷的工作原理?如果你在想遍歷數(shù)組時操作數(shù)組中每個元素,在 foreach 循環(huán)中使用引用會十分方便,例如

$arr = array(1, 2, 3, 4);foreach ($arr as &$value) {$value = $value * 2;}// $arr 現(xiàn)在是 array(2, 4, 6, 8)

問題是,如果你不注意的話這會導(dǎo)致一些意想不到的負面作用。在上述例子,在代碼執(zhí)行完以后,$value 仍保留在作用域內(nèi),并保留著對數(shù)組最后一個元素的引用。之后與 $value 相關(guān)的操作會無意中修改數(shù)組中最后一個元素的值。

你要記住 foreach 并不會產(chǎn)生一個塊級作用域。因此,在上面例子中 $value 是一個全局引用變量。在 foreach 遍歷中,每一次迭代都會形成一個對 $arr 下一個元素的引用。當(dāng)遍歷結(jié)束后, $value 會引用 $arr 的最后一個元素,并保留在作用域中

這種行為會導(dǎo)致一些不易發(fā)現(xiàn)的,令人困惑的bug,以下是一個例子

$array = [1, 2, 3];echo implode(',', $array), "n";foreach ($array as &$value) {} // 通過引用遍歷echo implode(',', $array), "n";foreach ($array as $value) {} // 通過賦值遍歷echo implode(',', $array), "n";

以上代碼會輸出

1,2,31,2,31,2,2

你沒有看錯,最后一行的最后一個值是 2 ,而不是 3 ,為什么?

在完成第一個 foreach 遍歷后, $array 并沒有改變,但是像上述解釋的那樣, $value 留下了一個對 $array 最后一個元素的危險的引用(因為 foreach 通過引用獲得 $value )

這導(dǎo)致當(dāng)運行到第二個 foreach ,這個"奇怪的東西"發(fā)生了。當(dāng) $value 通過賦值獲得, foreach 按順序復(fù)制每個 $array 的元素到 $value 時,第二個 foreach 里面的細節(jié)是這樣的

第一步:復(fù)制 $array[0] (也就是 1 )到 $value ($value 其實是 $array最后一個元素的引用,即 $array[2]),所以 $array[2] 現(xiàn)在等于 1。所以 $array 現(xiàn)在包含 [1, 2, 1]第二步:復(fù)制 $array[1](也就是 2 )到 $value ( $array[2] 的引用),所以 $array[2] 現(xiàn)在等于 2。所以 $array 現(xiàn)在包含 [1, 2, 2]第三步:復(fù)制 $array[2](現(xiàn)在等于 2 ) 到 $value ( $array[2] 的引用),所以 $array[2] 現(xiàn)在等于 2 。所以 $array 現(xiàn)在包含 [1, 2, 2]

為了在 foreach 中方便的使用引用而免遭這種麻煩,請在 foreach 執(zhí)行完畢后 unset() 掉這個保留著引用的變量。例如

$arr = array(1, 2, 3, 4);foreach ($arr as &$value) { $value = $value * 2;}unset($value); // $value 不再引用 $arr[3] 常見錯誤 #2: 誤解 isset() 的行為

盡管名字叫 isset,但是 isset() 不僅會在變量不存在的時候返回 false,在變量值為 null 的時候也會返回 false。

這種行為比最初出現(xiàn)的問題更為棘手,同時也是一種常見的錯誤源。

看看下面的代碼:

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

開發(fā)者想必是想確認 keyShouldBeSet 是否存在于 $data 中。然而,正如上面說的,如果 $data['keyShouldBeSet'] 存在并且值為 null 的時候, isset($data['keyShouldBeSet']) 也會返回 false。所以上面的邏輯是不嚴(yán)謹(jǐn)?shù)摹?/p>

我們來看另外一個例子:

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。

然而事實并非如此!

如我所言,如果$postData 存在且被設(shè)置為 null, isset($postData) 也會返回 false 。 也就是說,即使 $_POST['active'] 返回 true, isset($postData) 也可能會返回 false 。 再一次說明上面的邏輯不嚴(yán)謹(jǐn)。

順便一提,如果上面代碼的意圖真的是再次確認 $_POST['active'] 是否返回 true,依賴 isset() 來做,不管對于哪種場景來說都是一種糟糕的決定。更好的做法是再次檢查 $_POST['active'],即:

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

對于這種情況,雖然檢查一個變量是否真的存在很重要(即:區(qū)分一個變量是未被設(shè)置還是被設(shè)置為 null);但是使用 array_key_exists() 這個函數(shù)卻是個更健壯的解決途徑。

比如,我們可以像下面這樣重寫上面第一個例子:

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

另外,通過結(jié)合 array_key_exists() 和 get_defined_vars(), 我們能更加可靠的判斷一個變量在當(dāng)前作用域中是否存在:

if (array_key_exists('varShouldBeSet', get_defined_vars())) { // variable $varShouldBeSet exists in current scope} 常見錯誤 #3:關(guān)于通過引用返回與通過值返回的困惑

考慮下面的代碼片段:

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

出了什么問題?

上面代碼的問題在于沒有搞清楚通過引用與通過值返回數(shù)組的區(qū)別。除非你明確告訴 PHP 通過引用返回一個數(shù)組(例如,使用 &),否則 PHP 默認將會「通過值」返回這個數(shù)組。這意味著這個數(shù)組的一份拷貝將會被返回,因此被調(diào)函數(shù)與調(diào)用者所訪問的數(shù)組并不是同樣的數(shù)組實例。

所以上面對 getValues() 的調(diào)用將會返回 $values 數(shù)組的一份拷貝,而不是對它的引用。考慮到這一點,讓我們重新回顧一下以上例子中的兩個關(guān)鍵行:

// getValues() 返回了一個 $values 數(shù)組的拷貝// 所以`test`元素被添加到了這個拷貝中,而不是 $values 數(shù)組本身。$config->getValues()['test'] = 'test';// getValues() 又返回了另一份 $values 數(shù)組的拷貝// 且這份拷貝中并不包含一個`test`元素(這就是為什么我們會得到 「未定義索引」 消息)。echo $config->getValues()['test'];

一個可能的修改方法是存儲第一次通過 getValues() 返回的 $values 數(shù)組拷貝,然后后續(xù)操作都在那份拷貝上進行;例如:

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

這段代碼將會正常工作(例如,它將會輸出test而不會產(chǎn)生任何「未定義索引」消息),但是這個方法可能并不能滿足你的需求。特別是上面的代碼并不會修改原始的$values數(shù)組。如果你想要修改原始的數(shù)組(例如添加一個test元素),就需要修改getValues()函數(shù),讓它返回一個$values數(shù)組自身的引用。通過在函數(shù)名前面添加一個&來說明這個函數(shù)將返回一個引用;例如:

class Config{ private $values = []; // 返回一個 $values 數(shù)組的引用 public function &getValues() {return $this->values; }}$config = new Config();$config->getValues()['test'] = 'test';echo $config->getValues()['test'];

這會輸出期待的test。

但是現(xiàn)在讓事情更困惑一些,請考慮下面的代碼片段:

class Config{ private $values; // 使用數(shù)組對象而不是數(shù)組 public function __construct() {$this->values = new ArrayObject(); } public function getValues() {return $this->values; }}$config = new Config();$config->getValues()['test'] = 'test';echo $config->getValues()['test'];

如果你認為這段代碼會導(dǎo)致與之前的數(shù)組例子一樣的「未定義索引」錯誤,那就錯了。實際上,這段代碼將會正常運行。原因是,與數(shù)組不同,PHP 永遠會將對象按引用傳遞。(ArrayObject 是一個 SPL 對象,它完全模仿數(shù)組的用法,但是卻是以對象來工作。)

像以上例子說明的,你應(yīng)該以引用還是拷貝來處理通常不是很明顯就能看出來。因此,理解這些默認的行為(例如,變量和數(shù)組以值傳遞;對象以引用傳遞)并且仔細查看你將要調(diào)用的函數(shù) API 文檔,看看它是返回一個值,數(shù)組的拷貝,數(shù)組的引用或是對象的引用是必要的。

盡管如此,我們要認識到應(yīng)該盡量避免返回一個數(shù)組或 ArrayObject,因為這會讓調(diào)用者能夠修改實例對象的私有數(shù)據(jù)。這就破壞了對象的封裝性。所以最好的方式是使用傳統(tǒng)的「getters」和「setters」,例如:

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'); // 輸出『testValue』

這個方法讓調(diào)用者可以在不對私有的$values數(shù)組本身進行公開訪問的情況下設(shè)置或者獲取數(shù)組中的任意值。

 常見的錯誤 #4:在循環(huán)中執(zhí)行查詢

如果像這樣的話,一定不難見到你的 PHP 無法正常工作。

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

這里也許沒有真正的錯誤, 但是如果你跟隨著代碼的邏輯走下去, 你也許會發(fā)現(xiàn)這個看似無害的調(diào)用$valueRepository->findByValue() 最終執(zhí)行了這樣一種查詢,例如:

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

結(jié)果每輪循環(huán)都會產(chǎn)生一次對數(shù)據(jù)庫的查詢。 因此,假如你為這個循環(huán)提供了一個包含 1000 個值的數(shù)組,它會對資源產(chǎn)生 1000 單獨的請求!如果這樣的腳本在多個線程中被調(diào)用,他會有導(dǎo)致系統(tǒng)崩潰的潛在危險。

因此,至關(guān)重要的是,當(dāng)你的代碼要進行查詢時,應(yīng)該盡可能的收集需要用到的值,然后在一個查詢中獲取所有結(jié)果。

一個我們平時常常能見到查詢效率低下的地方 (例如:在循環(huán)中)是使用一個數(shù)組中的值 (比如說很多的 ID )向表發(fā)起請求。檢索每一個 ID 的所有的數(shù)據(jù),代碼將會迭代這個數(shù)組,每個 ID 進行一次SQL查詢請求,它看起來常常是這樣:

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

但是 只用一條 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; }}

因此在你的代碼直接或間接進行查詢請求時,一定要認出這種查詢。盡可能的通過一次查詢得到想要的結(jié)果。然而,依然要小心謹(jǐn)慎,不然就可能會出現(xiàn)下面我們要講的另一個易犯的錯誤...

 常見問題 #5: 內(nèi)存使用欺騙與低效

一次取多條記錄肯定是比一條條的取高效,但是當(dāng)我們使用 PHP 的 mysql 擴展的時候,這也可能成為一個導(dǎo)致 libmysqlclient 出現(xiàn)『內(nèi)存不足』(out of memory)的條件。

我們在一個測試盒里演示一下,該測試盒的環(huán)境是:有限的內(nèi)存(512MB RAM),MySQL,和 php-cli。

我們將像下面這樣引導(dǎo)一個數(shù)據(jù)表:

// 連接 mysql$connection = new mysqli('localhost', 'username', 'password', 'database');// 創(chuàng)建 400 個字段$query = 'CREATE TABLE `test`(`id` INT NOT NULL PRIMARY KEY AUTO_INCREMENT';for ($col = 0; $col < 400; $col++) { $query .= ", `col$col` CHAR(10) NOT NULL";}$query .= ');';$connection->query($query);// 寫入 2 百萬行數(shù)據(jù)for ($row = 0; $row < 2000000; $row++) { $query = "INSERT INTO `test` VALUES ($row"; for ($col = 0; $col < 400; $col++) {$query .= ', ' . mt_rand(1000000000, 9999999999); } $query .= ')'; $connection->query($query);}

OK,現(xiàn)在讓我們一起來看一下內(nèi)存使用情況:

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

輸出結(jié)果是:

Before: 224704Limit 1: 224704Limit 10000: 224704

Cool。 看來就內(nèi)存使用而言,內(nèi)部安全地管理了這個查詢的內(nèi)存。

為了更加明確這一點,我們把限制提高一倍,使其達到 100,000。 額~如果真這么干了,我們將會得到如下結(jié)果:

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

究竟發(fā)生了啥?

這就涉及到 PHP 的 mysql 模塊的工作方式的問題了。它其實只是個 libmysqlclient 的代理,專門負責(zé)干臟活累活。每查出一部分?jǐn)?shù)據(jù)后,它就立即把數(shù)據(jù)放入內(nèi)存中。由于這塊內(nèi)存還沒被 PHP 管理,所以,當(dāng)我們在查詢里增加限制的數(shù)量的時候, memory_get_peak_usage() 不會顯示任何增加的資源使用情況 。我們被『內(nèi)存管理沒問題』這種自滿的思想所欺騙了,所以才會導(dǎo)致上面的演示出現(xiàn)那種問題。 老實說,我們的內(nèi)存管理確實是有缺陷的,并且我們也會遇到如上所示的問題。

如果使用 mysqlnd 模塊的話,你至少可以避免上面那種欺騙(盡管它自身并不會提升你的內(nèi)存利用率)。 mysqlnd 被編譯成原生的 PHP 擴展,并且確實 會 使用 PHP 的內(nèi)存管理器。

因此,如果使用 mysqlnd 而不是 mysql,我們將會得到更真實的內(nèi)存利用率的信息:

Before: 232048Limit 1: 324952Limit 10000: 32572912

順便一提,這比剛才更糟糕。根據(jù) PHP 的文檔所說,mysql 使用 mysqlnd 兩倍的內(nèi)存來存儲數(shù)據(jù), 所以,原來使用 mysql 那個腳本真正使用的內(nèi)存比這里顯示的更多(大約是兩倍)。

為了避免出現(xiàn)這種問題,考慮限制一下你查詢的數(shù)量,使用一個較小的數(shù)字來循環(huán),像這樣:

$totalNumberToFetch = 10000;$portionSize = 100;for ($i = 0; $i <= ceil($totalNumberToFetch / $portionSize); $i++) { $limitFrom = $portionSize * $i; $res = $connection->query( "SELECT `x`,`y` FROM `test` LIMIT $limitFrom, $portionSize");}

當(dāng)我們把這個常見錯誤和上面的 常見錯誤 #4 結(jié)合起來考慮的時候, 就會意識到我們的代碼理想需要在兩者間實現(xiàn)一個平衡。是讓查詢粒度化和重復(fù)化,還是讓單個查詢巨大化。生活亦是如此,平衡不可或缺;哪一個極端都不好,都可能會導(dǎo)致 PHP 無法正常運行。

 常見錯誤 #6: 忽略 Unicode/UTF-8 的問題

從某種意義上說,這實際上是PHP本身的一個問題,而不是你在調(diào)試 PHP 時遇到的問題,但是它從未得到妥善的解決。 PHP 6 的核心就是要做到支持 Unicode。但是隨著 PHP 6 在 2010 年的暫停而擱置了。

這并不意味著開發(fā)者能夠避免 正確處理 UTF-8 并避免做出所有字符串必須是『古老的 ASCII』的假設(shè)。 沒有正確處理非 ASCII 字符串的代碼會因為引入粗糙的 海森堡bug(heisenbugs) 而變得臭名昭著。當(dāng)一個名字包含 『Schrödinger』的人注冊到你的系統(tǒng)時,即使簡單的 strlen($_POST['name']) 調(diào)用也會出現(xiàn)問題。

下面是一些可以避免出現(xiàn)這種問題的清單:

如果你對 UTF-8 還不了解,那么你至少應(yīng)該了解下基礎(chǔ)的東西。 這兒 有個很好的引子。確保使用 mb_* 函數(shù)代替老舊的字符串處理函數(shù)(需要先保證你的 PHP 構(gòu)建版本開啟了『多字節(jié)』(multibyte)擴展)。確保你的數(shù)據(jù)庫和表設(shè)置了 Unicode 編碼(許多 MySQL 的構(gòu)建版本仍然默認使用 latin1 )。記住 json_encode() 會轉(zhuǎn)換非 ASCII 標(biāo)識(比如: 『Schrödinger』會被轉(zhuǎn)換成 『Schru00f6dinger』),但是 serialize() 不會 轉(zhuǎn)換。確保 PHP 文件也是 UTF-8 編碼,以避免在連接硬編碼字符串或者配置字符串常量的時候產(chǎn)生沖突。

Francisco Claria 在本博客上發(fā)表的 UTF-8 Primer for PHP and MySQL 是份寶貴的資源。

 常見錯誤 #7: 認為 $_POST 總是包含你 POST 的數(shù)據(jù)

不管它的名稱,$_POST 數(shù)組不是總是包含你 POST 的數(shù)據(jù),他也有可能會是空的。 為了理解這一點,讓我們來看一下下面這個例子。假設(shè)我們使用 jQuery.ajax() 模擬一個服務(wù)請求,如下:

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

(順帶一提,注意這里的 contentType: 'application/json' 。我們用 JSON 類型發(fā)送數(shù)據(jù),這在接口中非常流行。這在 AngularJS $http service 里是默認的發(fā)送數(shù)據(jù)的類型。)

在我們舉例子的服務(wù)端,我們簡單的打印一下 $_POST 數(shù)組:

// phpvar_dump($_POST);

奇怪的是,結(jié)果如下:

array(0) { }

為什么?我們的 JSON 串 {a: 'a', b: 'b'} 究竟發(fā)生了什么?

原因在于 當(dāng)內(nèi)容類型為 application/x-www-form-urlencoded 或者 multipart/form-data 的時候 PHP 只會自動解析一個 POST 的有效內(nèi)容。這里面有歷史的原因 --- 這兩種內(nèi)容類型是在 PHP 的 $_POST 實現(xiàn)前就已經(jīng)在使用了的兩個重要的類型。所以不管使用其他任何內(nèi)容類型 (即使是那些現(xiàn)在很流行的,像 application/json), PHP 也不會自動加載到 POST 的有效內(nèi)容。

既然 $_POST 是一個超級全局變量,如果我們重寫 一次 (在我們的腳本里盡可能早的),被修改的值(包括 POST 的有效內(nèi)容)將可以在我們的代碼里被引用。這很重要因為 $_POST 已經(jīng)被 PHP 框架和幾乎所有的自定義的腳本普遍使用來獲取和傳遞請求數(shù)據(jù)。

所以,舉個例子,當(dāng)處理一個內(nèi)容類型為 application/json 的 POST 有效內(nèi)容的時候 ,我們需要手動解析請求內(nèi)容(decode 出 JSON 數(shù)據(jù))并且覆蓋 $_POST 變量,如下:

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

然后當(dāng)我們打印 $_POST 數(shù)組的時候,我們可以看到他正確的包含了 POST 的有效內(nèi)容;如下:

array(2) { ["a"]=> string(1) "a" ["b"]=> string(1) "b" } 常見錯誤 #8: 認為 PHP 支持單字符數(shù)據(jù)類型

閱讀下面的代碼并思考會輸出什么:

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

如果你的答案是 a 到 z,那么你可能會對這是一個錯誤答案感到吃驚。

沒錯,它確實會輸出 a 到 z,但是,它還會繼續(xù)輸出 aa 到 yz。我們一起來看一下這是為什么。

PHP 中沒有 char 數(shù)據(jù)類型; 只能用 string 類型。記住一點,在 PHP 中增加 string 類型的 z 得到的是 aa:

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

沒那么令人混淆的是,aa 的字典順序是 小于 z 的:

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

這也是為什么上面那段簡單的代碼會輸出 a 到 z, 然后 繼續(xù) 輸出 aa到 yz。 它停在了 za,那是它遇到的第一個比 z 大 的:

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

事實上,在 PHP 里 有合適的 方式在循環(huán)中輸出 a 到 z 的值:

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

或者是這樣:

$letters = range('a', 'z');for ($i = 0; $i < count($letters); $i++) { echo $letters[$i] . "n";} 常見 錯誤 #9: 忽視代碼規(guī)范

盡管忽視代碼標(biāo)準(zhǔn)并不直接導(dǎo)致需要去調(diào)試 PHP 代碼,但這可能是所有需要談?wù)摰氖虑槔镒钪匾囊豁棥?/p>

在一個項目中忽視代碼規(guī)范能夠?qū)е麓罅康膯栴}。最樂觀的預(yù)計,前后代碼不一致(在此之前每個開發(fā)者都在“做自己的事情”)。但最差的結(jié)果,PHP 代碼不能運行或者很難(有時是不可能的)去順利通過,這對于 調(diào)試代碼、提升性能、維護項目來說也是困難重重。并且這意味著降低你們團隊的生產(chǎn)力,增加大量的額外(或者至少是本不必要的)精力消耗。

幸運的是對于 PHP 開發(fā)者來說,存在 PHP 編碼標(biāo)準(zhǔn)建議(PSR),它由下面的五個標(biāo)準(zhǔn)組成:

PSR-0: 自動加載標(biāo)準(zhǔn)PSR-1: 基礎(chǔ)編碼標(biāo)準(zhǔn)PSR-2: 編碼風(fēng)格指導(dǎo)PSR-3: 日志接口PSR-4: 自動加載增強版

PSR 起初是由市場上最大的組織平臺維護者創(chuàng)造的。 Zend, Drupal, Symfony, Joomla 和 其他 為這些標(biāo)準(zhǔn)做出了貢獻,并一直遵守它們。甚至,多年前試圖成為一個標(biāo)準(zhǔn)的 PEAR ,現(xiàn)在也加入到 PSR 中來。

某種意義上,你的代碼標(biāo)準(zhǔn)是什么幾乎是不重要的,只要你遵循一個標(biāo)準(zhǔn)并堅持下去,但一般來講,跟隨 PSR 是一個很不錯的主意,除非你的項目上有其他讓人難以抗拒的理由。越來越多的團隊和項目正在遵從 PSR 。在這一點上,大部分的 PHP 開發(fā)者達成了共識,因此使用 PSR 代碼標(biāo)準(zhǔn),有利于使新加入團隊的開發(fā)者對你的代碼標(biāo)準(zhǔn)感到更加的熟悉與舒適。

 常見錯誤 #10: 濫用 empty()

一些 PHP 開發(fā)者喜歡對幾乎所有的事情使用 empty() 做布爾值檢驗。不過,在一些情況下,這會導(dǎo)致混亂。

首先,讓我們回到數(shù)組和 ArrayObject 實例(和數(shù)組類似)。考慮到他們的相似性,很容易假設(shè)它們的行為是相同的。然而,事實證明這是一個危險的假設(shè)。舉例,在 PHP 5.0 中:

// PHP 5.0 或后續(xù)版本:$array = [];var_dump(empty($array));// 輸出 bool(true)$array = new ArrayObject();var_dump(empty($array));// 輸出 bool(false)// 為什么這兩種方法不產(chǎn)生相同的輸出呢?

更糟糕的是,PHP 5.0之前的結(jié)果可能是不同的:

// PHP 5.0 之前:$array = [];var_dump(empty($array));// 輸出 bool(false)$array = new ArrayObject();var_dump(empty($array));// 輸出 bool(false)

這種方法上的不幸是十分普遍的。比如,在 Zend Framework 2 下的 ZendDbTableGateway 的 TableGateway::select() 結(jié)果中調(diào)用 current() 時返回數(shù)據(jù)的方式,正如文檔所表明的那樣。開發(fā)者很容易就會變成此類數(shù)據(jù)錯誤的受害者。

為了避免這些問題的產(chǎn)生,更好的方法是使用 count() 去檢驗空數(shù)組結(jié)構(gòu):

// 注意這會在 PHP 的所有版本中發(fā)揮作用 (5.0 前后都是):$array = [];var_dump(count($array));// 輸出 int(0)$array = new ArrayObject();var_dump(count($array));// 輸出 int(0)

順便說一句, 由于 PHP 將 0 轉(zhuǎn)換為 false , count() 能夠被使用在 if() 條件內(nèi)部去檢驗空數(shù)組。同樣值得注意的是,在 PHP 中, count() 在數(shù)組中是常量復(fù)雜度 (O(1) 操作) ,這更清晰的表明它是正確的選擇。

另一個使用 empty() 產(chǎn)生危險的例子是當(dāng)它和魔術(shù)方法 _get() 一起使用。我們來定義兩個類并使其都有一個 test 屬性。

首先我們定義包含 test 公共屬性的 Regular 類。

class Regular{ public $test = 'value';}

然后我們定義 Magic 類,這里使用魔術(shù)方法 __get() 來操作去訪問它的 test 屬性:

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

好了,現(xiàn)在我們嘗試去訪問每個類中的 test 屬性看看會發(fā)生什么:

$regular = new Regular();var_dump($regular->test); // 輸出 string(4) "value"$magic = new Magic();var_dump($magic->test); // 輸出 string(4) "value"

到目前為止還好。

但是現(xiàn)在當(dāng)我們對其中的每一個都調(diào)用 empty() ,讓我們看看會發(fā)生什么:

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

咳。所以如果我們依賴 empty() ,我們很可能誤認為 $magic 的屬性 test 是空的,而實際上它被設(shè)置為 'value'。

不幸的是,如果類使用魔術(shù)方法 __get() 來獲取屬性值,那么就沒有萬無一失的方法來檢查該屬性值是否為空。

在類的作用域之外,你僅僅只能檢查是否將返回一個 null 值,這并不意味著沒有設(shè)置相應(yīng)的鍵,因為它實際上還可能被設(shè)置為 null 。

相反,如果我們試圖去引用 Regular 類實例中不存在的屬性,我們將得到一個類似于以下內(nèi)容的通知:

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

所以這里的主要觀點是 empty() 方法應(yīng)該被謹(jǐn)慎地使用,因為如果不小心的話它可能導(dǎo)致混亂 -- 甚至潛在的誤導(dǎo) -- 結(jié)果。

 總結(jié)

PHP 的易用性讓開發(fā)者陷入一種虛假的舒適感,語言本身的一些細微差別和特質(zhì),可能花費掉你大量的時間去調(diào)試。這些可能會導(dǎo)致 PHP 程序無法正常工作,并導(dǎo)致諸如此處所述的問題。

PHP 在其20年的歷史中,已經(jīng)發(fā)生了顯著的變化。花時間去熟悉語言本身的微妙之處是值得的,因為它有助于確保你編寫的軟件更具可擴展性,健壯和可維護性。

標(biāo)簽: PHP
相關(guān)文章:
主站蜘蛛池模板: 久久性视频 | 33eee在线视频免费观看 | 国产一级黄色av | 一级一片免费视频 | 中文字幕91| 国产一级黄色大片 | 国产美女在线观看 | 欧美美女爱爱视频 | 欧美精品综合 | 一区二区av在线 | 亚洲视频免费 | 久久777| 久久久久久一区 | 在线免费观看黄 | 嫩草精品 | 日中文字幕在线 | 婷婷在线视频 | 亚洲网色 | 成人午夜性a一级毛片免费看 | 亚洲黄色成人 | 日本中文字幕视频 | 青青久久久 | 色橹橹欧美在线观看视频高清 | 国内精品一区二区三区 | 日韩中文字幕av | 久久99一区二区 | 午夜草逼| 精品免费 | 久久天堂| 亚洲一级黄色 | 亚洲一区国产精品 | 成人一区二区三区久久精品嫩草 | 国产午夜精品久久 | 国产欧美久久久久久 | 一区二区三区亚洲 | 亚洲国产欧美一区二区三区久久 | 久久综合一区二区三区 | 一区二区日韩精品 | 国产成人啪精品午夜在线观看 | 欧美一级日韩 | 免费在线国产 | 久久精品91| 亚洲一区二区在线视频 | 黄网站免费在线观看 | 欧美日韩一区在线观看 | 国产精品久久久久aaaa九色 | 亚洲视频免费网站 | 日韩一区二区精品视频 | 国产黄色在线观看 | 亚洲激情在线观看 | 欧美日韩在线视频观看 | 亚洲国产一区二区三区四区 | 免费在线a| 黄色一级大片视频 | 日韩美香港a一级毛片免费 国产综合av | 久久久久久久久久国产 | 国产四区 | 欧美精品一区自拍a毛片在线视频 | 日韩精品一区二区三区在线播放 | 国产精品国产精品国产专区不片 | 欧美精品免费在线观看 | 日韩1区 | 一区二区在线视频 | 欧美激情网 | 色爽av| 亚洲国产二区 | 午夜一级黄色片 | 国产精品亚洲视频 | a级网站在线观看 | 午夜视频网 | 影音先锋中文字幕在线 | 亚洲精品电影在线观看 | 久久亚洲精品国产精品紫薇 | 四色成人av永久网址 | 日本久久久久 | 99国内精品久久久久久久 | hitomi一区二区三区精品 | 在线免费看黄视频 | 荡女妇边被c边呻吟视频 | 国产精品久久久久久亚洲调教 | 国产精品大全 | 日本高清视频网站 | 精品国产欧美一区二区 | 91社区在线高清 | 国产亚洲欧美一区二区 | 一区二区亚洲 | 日本另类αv欧美另类aⅴ | 国产一级黄色大片 | 免费中文字幕日韩欧美 | 亚洲在线播放 | 久久免费电影 | 亚洲网站在线观看 | 欧美性猛交一区二区三区精品 | 国产视频久久久 | 久久久久久久久久久网站 | 国产视频黄在线观看 | 天天干人人 | 亚洲一区二区av | 亚洲国产精品99久久久久久久久 | 国产成在线观看免费视频 | 91视频原创| 精品久久久久久久久久久久久久 | a视频在线免费观看 | 欧美一区二区三区免费电影 | 国产成人无遮挡在线视频 | 亚洲精品国产一区 | 免费爱爱视频 | 国产传媒一区 | 女朋友的闺蜜3韩国三级 | 日本不卡一区二区 | 国产一区二区三区在线免费观看 | 99精品国产高清在线观看 | 国产精品久久久久久久久福交 | 91久久精品一区二区三区 | 国产精品久久久久久久久免费软件 | 欧美在线观看一区二区 | 国产女精品 | 欧美精品成人 | 精品国产一区二区三区小蝌蚪 | 国产精品18hdxxxⅹ在线 | 久久噜噜噜精品国产亚洲综合 | 亚洲欧美日韩另类精品一区二区三区 | 999免费视频 | 中文字幕在线资源 | 日本久久久一区二区三区 | 国产美女av| 久草免费在线视频 | 亚洲综合色自拍一区 | 欧美日韩黄色一级片 | 亚洲综合在线一区二区 | 91玖玖| va在线| 国产精品一区二区不卡 | 一区二区三区在线播放 | 久久成人一区 | 欧美黄色大片网站 | 国产成人综合网 | 黄色一级免费看 | 日韩中文字幕在线观看 | 一区毛片| 久久2018 | 亚洲1级片 | 91看片在线观看 | 成人精品视频99在线观看免费 | 中文字幕黄色 | 久久社区 | 影视在线观看 | 国产一区二区三区免费在线观看 | 一级a毛片 | 久久久久久久久综合 | 99精品欧美一区二区三区 | 二区在线视频 | 中国妞videos高潮 | 成人黄色片网站 | 伊人av在线 | 欧美亚洲免费 | 国产精品久久久久久久久久免费看 | 国产精品美女久久久久久久久久久 | 国产毛片av | 99久久久久久 | 欧美日韩在线观看中文字幕 | 色欧美日韩 | 色爱综合 | 精品一区二区三区久久久 | 毛片免费在线 | 国产日皮视频 | 午夜操操| 欧美人成在线观看 | 成年人综合网 | 91久久久久 | 在线成人av | 亚洲午夜免费视频 | 成人欧美一区二区三区色青冈 | 亚洲视频一区二区三区 | 色成人免费网站 | 亚洲视频区 | 免费一区二区三区 | 国产婷婷综合 | 一区在线观看 | 狠狠入ady亚洲精品经典电影 | 亚洲精品乱码久久久久久 | 久久国产成人 | 黄色一级毛片免费 | 欧美xxxx色视频在线观看免费 | 亚洲成人精品在线观看 | 久久99操 | 有码一区 | 欧美精品二区中文乱码字幕高清 | 国产精品亚洲区 | 九九综合九九 | 成人av网址在线观看 | 艹逼逼视频 | 一区二区三区日韩 | 日韩成人免费 | 一区二区久久 | 国产中文| 亚洲国产免费 | 成人h漫在线观看 | 成人欧美一区二区三区在线观看 | 精品一区二区三区四区 | 久久久一 | 久久久精品一区二区三区 | 欧美成人高清视频 | 日本在线播放 | 亚洲电影中文字幕 | 91观看在线视频 | 91久久夜色精品国产网站 | 久久精品a一级国产免视看成人 | www久久久| 亚洲欧洲精品视频在线观看 | 天天操导航 | 看真人视频a级毛片 | 国产精品欧美一区二区三区 | 亚洲 欧美 另类 综合 偷拍 | 精品成人佐山爱一区二区 | 成人性生交大片免费看中文带字幕 | 91.成人天堂一区 | 91久久国产综合久久91精品网站 | 亚洲一区中文字幕在线 | 欧美精品一区二区在线观看 | 国产视频亚洲精品 | 久久精品久久久久久久久久久久久 | 国产激情在线观看 | 日韩欧美一区二区视频 | 久久99精品久久久久蜜臀 | 成人欧美日韩一区二区三区 | 最新国产成人 | 亚洲综合福利视频 | 成人亚洲一区 | 午夜窝窝| 91精品国产综合久久婷婷香蕉 | 久久国产一区二区三区 | 婷婷精品视频 | 九九热这里只有精品8 | 香蕉久久av一区二区三区 | 欧美一级黄 | 国产精品久久久久久久天堂 | 在线观看一区二区三区四区 | 91视频一区二区三区 | 亚洲欧美在线免费 | 国产精品69毛片高清亚洲 | 久久线视频 | 亚洲一区二区三区四区在线观看 | 男女羞羞视频免费看 | 免费成人激情视频 | 国产视频网 | 国产精品国产 | 色综合免费视频 | 成人不卡 | 国产一区二区欧美 | 综合久久综合 | 亚洲国产精久久久久久久 | 一区二区三区视频 | 黄视频网站免费观看 | 欧美日韩视频一区二区 | 欧美第一页 | 亚洲欧美日韩精品久久奇米色影视 | 亚洲一区中文字幕 | 互换娇妻呻吟hd中文字幕 | 婷婷在线视频 | 91福利在线播放 | 久久久久久亚洲精品 | 91在线精品一区二区 | 韩国精品视频在线观看 | 成人精品免费视频 | 精品国产乱码久久久久久蜜臀 | 中文字幕在线观看2021 | 成人精品网站在线观看 | 国产99久久久久久免费看农村 | 国产成人综合av | 美女天天操| 久久二| 精品久| 亚洲国产精品久久久久秋霞蜜臀 | 午夜午夜精品一区二区三区文 | 亚洲视频在线视频 | 精品国产91亚洲一区二区三区www | 伊人网在线 | 日韩国产在线观看 | 一区二区精品在线观看 | www.一区 | 国产精品免费在线 | 欧美黄色精品 | 日韩毛片免费在线观看 | 亚洲成人av在线 | 国产一区免费视频 | 国产精品视频免费观看 | cao视频| 免费观看一级特黄欧美大片 | 久久精av | 亚洲人成在线播放 | 久久久xx| 亚洲a级在线观看 | 国产成人精品免费 | 91精品国产自产91精品 | 羞羞视频在线观看入口 | 国产区久久 | 天堂在线中文 | 午夜亚洲福利 | 一级毛片免费看 | 91精品电影| 一区二区三区视频 | 欧美午夜精品久久久久免费视 | 黄色免费网址大全 | 91黄在线观看 | 欧美精品在线一区 | heyzo在线观看| 欧美一极片 | 日韩久久精品一区二区 | 日韩午夜影院 | 亚洲国产婷婷香蕉久久久久久99 | 一区二区三区视频 | 国产在线小视频 | 亚洲精品电影在线观看 | 国产高清精品一区二区三区 | 国产黄色在线免费看 | 久久九九国产精品 | 国产精品一二三区 | 荡女妇边被c边呻吟视频 | 国产精品久久久久久久久久 | 亚洲高清不卡视频 | 毛片日韩| 国产精品乱码人人做人人爱 | 亚洲视频在线观看 | 国产免费一区二区三区最新不卡 | 精品欧美乱码久久久久久 | 亚洲在线成人 | 欧美色成人 | 国产黄色大片免费观看 | 91中文字幕在线 | 精品久久久久久久人人人人传媒 | 日本一区二区三区免费观看 | 欧美∨a| 中国特黄毛片 | 最新国产中文字幕 | 欧美日韩成人在线播放 | 亚洲精品久久久久久久久久久 | 亚洲aⅴ | 成人午夜免费视频 | 亚洲天堂一区 | 午夜精品久久 | 久久久久久久久久毛片 | 日韩av在线不卡 | 欧美成人一级 | 亚洲成人毛片 | 婷婷综合久久 | 国产精品成人3p一区二区三区 | 免费观看国产视频在线 | 狠狠色综合色综合网络 | 亚洲h网站| 夜夜艹| 日韩伦理一区二区 | 亚洲国产精品视频 | 91中文字幕 | av高清在线免费观看 | 在线成人免费观看www | 国产亚洲欧美在线 | 久久久久久艹 | 91精品一区二区三区久久久久久 | 噜噜噜噜噜在线视频 | 中文字幕在线观看 | 国产黄色影视 | 91色在线观看 | 欧美黄色片 | 精品欧美乱码久久久久久 | 久久精品中文 | 99在线视频播放 | 一区二区视频在线 | 国内精品久久久久久中文字幕 | 亚洲激情视频在线播放 | 婷婷丁香五 | 999在线观看视频 | 91精品国产综合久久婷婷香蕉 | 在线看片网站 | 精品视频一区二区在线观看 | 99热在线看| 精品国产一区二区三区日日嗨 | 久久久精品免费观看 | 天堂久久精品 | 国产一区二区三区不卡在线观看 | 综合久久99 | 日韩成人一级片 | 欧美日韩在线看 | 欧美自拍视频一区 | 中文字幕亚洲在线 | 国产高清视频一区二区 | 男女羞羞视频免费观看 | 亚洲福利一区二区 | 精品无码久久久久国产 | 亚洲最新av | 福利视频网址导航 | 国产精品毛片一区二区在线看 | 97色在线观看免费视频 | 久久久久久国产免费视网址 | 国产午夜精品久久 | 亚洲精品aaa | www97影院 | 国产精品久久久久久久久晋中 | 欧美日韩精品一区二区三区蜜桃 | 国产精品高清在线 | 国产日韩欧美一区二区 | 精品国产一区二区 | 岛国av免费看 | 日韩欧美视频一区 | 免费看的黄色网 | 亚洲依人| 免费国产一区 | 欧美午夜一区二区三区免费大片 | 成人在线不卡 | 天天夜夜操 | 艳妇荡乳豪妇荡淫 | 欧美视频网站 | 北条麻妃99精品青青久久 | 欧美一区二区三区黄 | 国产精品无码久久久久 | 国产一区二区三区免费 | 午夜精品福利在线观看 | 亚洲综合欧美 | 国产一区91| 亚洲成人日本 | 天天插天天射天天干 | 亚洲www永久成人夜色 | 免费视频久久 | 99色播| 欧美日韩国产一区 | 99精品热 | 亚洲精品视频免费看 | 天天综合网91 | 在线观看免费av网 | 久久成人免费 | www.av欧美| 国产欧美精品在线 | 91精品国产综合久久久久久丝袜 | 欧美1区 | 国产一区二区三区在线看 | 日本欧美国产 | 91影院| 玖玖综合网 | 亚洲国产精品麻豆 | 91精品国产欧美一区二区成人 | 日本不卡免费新一二三区 | 亚洲网在线| 国产在线不卡 | 久久av综合网 | 午夜精品久久久久久久白皮肤 | 国产在线观看免费 | 午夜视频网 | 天天躁日日躁性色aⅴ电影 免费在线观看成年人视频 国产欧美精品 | 精品一区二区三区四区 | 亚洲欧美日韩在线一区二区三区 | 久热免费在线观看 | 亚洲精品夜夜夜 | 爱干视频 | 亚洲精品乱码久久久久久国产主播 | 成人精品久久久 | 亚洲小视频 | 国产精品一区av | 亚洲美女视频一区二区三区 | 特黄特色大片免费视频观看 | 成人黄色a | 九一视频在线免费观看 | 欧美精品在线一区 | 久久综合社区 | 男人的天堂在线视频 | 欧美一性一交 | 一区二区三区在线 | 欧 | 精品国产精品三级精品av网址 | 午夜影院在线观看视频 | 精品久久久久久久久久久久 | 久草新视频在线观看 | 一级片大全| 狠狠色综合久久丁香婷婷 | 精品久久久久国产免费 | 91精品国产福利在线观看 | 一级黄片毛片 | 超碰免费观看 | 国产精品18久久久久久久久久久久 | 精品国产乱码久久久久久久软件 | 中文一区二区 | 国产欧美日韩中文字幕 | 亚洲人成网站999久久久综合 | 1级毛片| 亚洲综合视频 | 女人爽到高潮aaaa电影 | 久久久久久久久久久九 | 日韩成人片 | 33eee在线视频免费观看 | 日韩成人免费电影 | 国产欧美精品一区二区 | 亚洲成人av在线 | 国产www网站 | 久久久久久久久国产 | 麻豆产精国品免费入口 | 免费观看成人性生生活片 | 国产精品九九九 | 久久久精品影院 | 欧美夜夜爽 | 久久在线视频 | 亚洲高清精品视频 | 国产精品久久久久久久岛一牛影视 | 免费成人在线网站 | 免费在线亚洲 | 日韩一区二区三区在线视频 | 日韩xxxbbb| 中文久久| 日韩一区在线观看视频 | 91久久爽久久爽爽久久片 | 久久精品欧美一区二区三区不卡 | 国产精品一区二区三区四区 | 亚洲骚片 | 日韩精品一区二区三区在线 | 国产精品视频一区二区三区四蜜臂 | www日韩 | 97人人草 | 美女黄视频网站 | 一区二区在线播放视频 | 91综合在线观看 | 最新中文字幕在线 | 另类sb东北妇女av | 精品视频一区二区三区 | 青草视频网站 | 日本免费视频 | 国产精品美女久久久久aⅴ国产馆 | 美国一级毛片a | 一区二区三区国产好的精 | 大香萑| 亚洲午夜视频在线观看 | 国产日韩精品入口 | 午夜合集 | 中文字幕精品一区久久久久 | 亚洲一区精品视频 | 伊人激情综合网 | 男女网站视频 | jav成人av免费播放 | 91中文字幕 | 中文字幕亚洲在线观看 | 在线成人免费观看www | 欧美美乳| 免费午夜电影 | 亚洲精品一区中文字幕乱码 | 精品久久久久久久久久久久久久 | 日本亚洲视频 | 欧洲精品乱码久久久久蜜桃 | 欧美一级c片| 亚洲欧美中文日韩在线v日本 | 亚洲国产成人久久 | 欧美精品成人一区二区三区四区 | 欧美一级免费播放 | 欧美国产一区二区 | 91亚洲精品乱码久久久久久蜜桃 | 一区二区国产精品 | 99精品视频一区二区三区 | 国产欧美日韩综合精品一区二区 | 成年人av网站| 69av.com| 国产精品国产成人国产三级 | 精品国产乱码久久久久久蜜臀 | 一区二区成人网 | 日韩一区二区三区在线观看 | 一级欧美一级日韩 | 91久久久久久 | 日韩国产欧美 | 久久久久国产精品www | 国产中文字幕在线 | 日日爱999| 午夜精品久久久久久久男人的天堂 | 国产99久久久久久免费看农村 | 日韩二区三区 | 欧美在线播放一区 | 麻豆国产露脸在线观看 | 青青草超碰在线 | 亚洲精品久久久一区二区三区 | 国产精品视频一二三 | 久久精品久| 日本一区二区三区四区 | 午夜影视 | 福利在线看 | 国产精品乱码一区二区三区 | 午夜视频在线 | 久热中文 | 成人午夜精品一区二区三区 | 成人在线视频网址 | 日本综合色 | 久久精品国产一区二区电影 | 久久久久国产一区二区三区 | 一级人爱视频 | 色婷婷导航 | 久久精品色欧美aⅴ一区二区 | 成人免费xxxxxx视频 | 日本中文字幕在线视频 | 激情综合久久 | 中文字幕免费看 | 蜜臀网| 亚洲综合无码一区二区 | 国产在线小视频 | 在线不卡a资源高清 | 国产精品毛片一区二区 | av成人免费在线观看 | 日韩电影一区二区三区 | 91成人在线免费视频 | 亚洲一区二区三区 | 一区二区三区视频在线观看 | 国产精品久久久久影院色老大 | 欧美日韩免费看 | 激情久久av一区av二区av三区 | 国产精品视频一区二区三区四 | 日韩中文不卡 | 一级片在线观看 | 国内精品一区二区三区 | av中文字幕网 | 91尤物网站网红尤物福利 | 亚洲精品1区2区 | 欧美成人精品一区二区三区 | 亚洲伊人中文字幕 | 天天宗合网 |