1 問題起源
問題源於細說PHP的教學視頻:PHP設計超級好用的檔案上傳處理類。視頻中在建構函式中採用了數組來傳參數,然後根據這些參數名是否是類的成員名來給成員賦值。程式碼片段如下:
1 <?php
2 class FileUpload
3 {
4 //指定上傳路徑,允許的類型,限制檔案大小,是否使用隨機檔案名稱
5 private $file_path;
6 private $allowed_types = array('gif', 'png', 'jpg', 'jpeg');
7 private $max_size = 100000;
8 private $name_random = true;
9
10 function __construct($options) {
11 foreach($options as $key=>$value) {
12 $key = strtolower($key);
13 $vars = get_class_vars(get_class($this));
14 if(!in_array($key, $vars)) {
15 continue;
16 }
17 $this->$key = $value;
18 }
19 }
20
21 function __destruct() {
22 }
23 }
首先說明的是,這裡不應該使用in_array(),因為in_array是判斷數組元素的值而不是元素的索引索引值,這一點在《細說PHP》第二版371頁已經改成是array_key_exists了。
然而上述函數在這裡卻歪打正著地好用,因為實際上,無論傳入什麼樣的參數,均會在第14行中的in_array()返回true,我們要分析的就是為什麼總返回true。
2 原因分析問題就出在了第8行,這裡有一個成員的值是true。PHP在做比較時,當進行比較的兩個實值型別不同的時候,會自動轉型,規則如下:
null 或string |
string |
將 NULL 轉換為 "",進行數字或詞彙比較 |
bool 或null |
任何其它類型 |
轉換為 bool,FALSE <TRUE |
object |
object |
內建類可以定義自己的比較,不同類不能比較,相同類和數組同樣方式比較屬性(PHP 4 中),PHP 5 有其自己的說明 |
string,resource 或number |
string,resource 或number |
將字串和資源轉換成數字,按普通數學比較 |
array |
array |
具有較少成員的數組較小,如果運算數 1 中的鍵不存在於運算數 2 中則數組無法比較,否則挨個值比較(見下例) |
array |
任何其它類型 |
array 總是更大 |
object |
任何其它類型 |
object 總是更大 |
顯然,這裡命中了第二條規則,因為調用者傳入的是字串,一旦和這個true進行比較時,字串只要是非空,那麼比較前就會自動轉為bool值的true,當然true==true。
對此的簡化模型如下:in_array(任何非Null 字元串,array(元素1,元素2...., true));此函數總是返回true。3 總結體會(1)使用PHP函數時,一定要弄清楚其正確的含義,比如這裡的in_array就應該改成array_key_exists.(2)PHP這種軟類型的自動類型轉換非常頻繁,需要倍加註意。其實in_array()裡也對此提供了第三個選擇性參數,來進一步確定是否使用===而不是==。