php是一種弱類型的編程語言。在php程序中,變量的數據類型可以隨著其值的不同而自動發生改變,php也不會對變量的數據類型進行強制檢查或約束
我們可以參考下面一個簡單的代碼示例:
代碼如下 復制代碼
<?php
class Person {
}
$a = 1; //此時,$a為整數類型型(Integer)
var_dump($a);
$a = 1.0; //此時,$a為浮點類型(Float)
var_dump($a);
$a = 'CodePlayer'; //此時,$a為字符串類型(String)
var_dump($a);
$a = array('CodePlayer' => 'http://www.bKjia.c0m'); //此時,$a為數組類型(Array)
var_dump($a);
$a = new Person(); //此時,$a為Person對象類型(Object)
var_dump($a);
$a = mysql_connect('localhost', 'username', 'password'); //此時,$a為資源類型(Resource)
var_dump($a);
?>
對應的運行效果如下圖所示:
php弱數據類型的特點使得php使用起來顯得簡單而靈活。不過,這同樣也是一把達摩克利斯之劍。也正是由於php弱數據類型的特點,在編寫php程序代碼時,開發人員更需要時刻注意變量數據類型的變化,尤其是變量作為函數的參數進行傳遞時,更需要注意這一點。畢竟,大多數的函數參數都只期望是某種特定的數據類型。例如,在下面的例子中,函數sayHi()期望接收的參數類型是Person對象類型,但是,由於php並不是強類型的語言,也不會強制檢查變量的類型,因此我們可以向函數中傳遞任意類型的參數,從而導致程序報錯或邏輯出現異常。
<?php
class Person {
public $name = 'CodePlayer';
public $age = 3;
}
function sayHi($person){
echo "Hello! My name is $person->name. I'm $person->age years old.";
}
$p = '張三';
sayHi($p); //不是期望的Person對象類型,將出現Notice級別錯誤信息,程序仍然繼續運行
echo 'Suffix'; //仍然會輸出該文本信息
?>
從php 5開始,我們就可以使用新增的類型約束機制來對函數參數的部分數據類型進行類型約束。同樣以上面的代碼為例,我們可以在編寫sayHi()函數時要求傳遞進來的參數必須是Person對象類型,否則引發致命錯誤(Fatal Error),並終止當前頁面腳本的運行。要使用php的類型約束機制非常簡單,我們只需要在函數聲明的參數變量前添加指定的類型名稱即可。當我們調用該函數時,php會強制檢查函數的參數是否為指定的類型,如果不是指定的類型則引發致命錯誤。
代碼如下 復制代碼 <?php
class Person {
public $name = 'CodePlayer';
public $age = 3;
}
function sayHi(Person $person){
echo "Hello! My name is $person->name. I'm $person->age years old.";
}
$person = '張三';
sayHi($person); //不是期望的Person對象類型,引發Fatal Error致命錯誤,程序終止運行
echo 'Suffix'; //不會輸出該文本信息,程序終止運行
?>
值得注意的是,在php 5中,目前只有對象、接口、數組、callable類型的參數變量才能使用類型約束(數組類型是從php 5.1版本開始支持的,callable類型是從php 5.4版本開始支持的)。
注意:如果使用類型約束的參數變量沒有聲明其默認值為null,調用該函數時就不能給對應的參數變量傳遞null值,否則同樣也會報錯。
類型約束不能用於標量類型如 int 或 string。Traits 也不允許。
Example #1 類型約束示例
代碼如下 復制代碼<?php
//如下面的類
class MyClass
{
/**
* 測試函數
* 第一個參數必須為 OtherClass 類的一個對象
*/
public function test(OtherClass $otherclass) {
echo $otherclass->var;
}
/**
* 另一個測試函數
* 第一個參數必須為數組
*/
public function test_array(array $input_array) {
print_r($input_array);
}
}
/**
* 第一個參數必須為遞歸類型
*/
public function test_interface(Traversable $iterator) {
echo get_class($iterator);
}
/**
* 第一個參數必須為回調類型
*/
public function test_callable(callable $callback, $data) {
call_user_func($callback, $data);
}
}
// OtherClass 類定義
class OtherClass {
public $var = 'Hello World';
}
?>
函數調用的參數與定義的參數類型不一致時,會拋出一個可捕獲的致命錯誤。
代碼如下 復制代碼<?php
// 兩個類的對象
$myclass = new MyClass;
$otherclass = new OtherClass;
// 致命錯誤:第一個參數必須是 OtherClass 類的一個對象
$myclass->test('hello');
// 致命錯誤:第一個參數必須為 OtherClass 類的一個實例
$foo = new stdClass;
$myclass->test($foo);
// 致命錯誤:第一個參數不能為 null
$myclass->test(null);
// 正確:輸出 Hello World
$myclass->test($otherclass);
// 致命錯誤:第一個參數必須為數組
$myclass->test_array('a string');
// 正確:輸出數組
$myclass->test_array(array('a', 'b', 'c'));
// 正確:輸出 ArrayObject
$myclass->test_interface(new ArrayObject(array()));
// 正確:輸出 int(1)
$myclass->test_callable('var_dump', 1);
?>
類型約束不只是用在類的成員函數裡,也能使用在函數裡:
代碼如下 復制代碼<?php
// 如下面的類
class MyClass {
public $var = 'Hello World';
}
/**
* 測試函數
* 第一個參數必須是 MyClass 類的一個對象
*/
function MyFunction (MyClass $foo) {
echo $foo->var;
}
// 正確
$myclass = new MyClass;
MyFunction($myclass);
?>
類型約束允許 NULL 值:
<?php
/* 接受 NULL 值 */
function test(stdClass $obj = NULL) {
}
test(NULL);
test(new stdClass);
?>