11.異常處理
用戶可以用自定義的異常處理類來擴展 PHP 內置的異常處理類。以下的代碼說明了在內置的異常處理類中,哪些屬性和方法在子類中是可訪問和可繼承的。譯者注:以下這段代碼只為說明內置異常處理類的結構,它並不是一段有實際意義的可用代碼。
<?php
class Exception{
protected $message = 'Unknown exception'; // 異常信息
protected $code = 0; // 用戶自定義異常代碼
protected $file; // 發生異常的文件名
protected $line; // 發生異常的代碼行號
function __construct($message = null, $code = 0);
final function getMessage(); // 返回異常信息
final function getCode(); // 返回異常代碼
final function getFile(); // 返回發生異常的文件名
final function getLine(); // 返回發生異常的代碼行號
final function getTrace(); // backtrace() 數組
final function getTraceAsString(); // 已格成化成字符串的 getTrace() 信息
/* 可重載的方法 */
function __toString(); // 可輸出的字符串
}
?>
如果使用自定義的類來擴展內置異常處理類,並且要重新定義構造函數的話,建議同時調用 parent::__construct()來檢查所有的變量是否已被賦值。當對象要輸出字符串的時候,可以重載 __toString() 並自定義輸出的樣式。
擴展 PHP 內置的異常處理類
<?php
// 自定義一個異常處理類
class MyException extends Exception{ // 重定義構造器使 message 變為必須被指定的屬性
public function __construct($message, $code = 0) {
// 自定義的代碼 // 確保所有變量都被正確賦值
parent::__construct($message, $code);
}
// 自定義字符串輸出的樣式
public function __toString() {
return __CLASS__ . ": [{$this->code}]: {$this->message}\n";
}
public function customFunction() {
echo "A Custom function for this type of exception\n";
}
}
//創建一個用於測試異常處理機制的類
class TestException{
public $var;
const THROW_NONE = 0;
const THROW_CUSTOM = 1;
const THROW_DEFAULT = 2;
function __construct($avalue = self::THROW_NONE) {
switch ($avalue) {
case self::THROW_CUSTOM:
// 拋出自定義異常
throw new MyException('1 is an invalid parameter', 5);
break;
case self::THROW_DEFAULT:
// 拋出默認的異常
throw new Exception('2 isnt allowed as a parameter', 6);
break;
default:
// 沒有異常的情況下,創建一個對象
$this->var = $avalue;
break;
}
}
}
// 例子 1
try {
$o = new TestException(TestException::THROW_CUSTOM);
} catch (MyException $e) { // 捕獲異常
echo "Caught my exception\n", $e;
$e->customFunction();
} catch (Exception $e) { // 被忽略
echo "Caught Default Exception\n", $e;
}
// 執行後續代碼
var_dump($o);
echo "\n\n";
// 例子 2
try {
$o = new TestException(TestException::THROW_DEFAULT);
} catch (MyException $e) { // 不能匹配異常的種類,被忽略
echo "Caught my exception\n", $e;
$e->customFunction();
} catch (Exception $e) { // 捕獲異常
echo "Caught Default Exception\n", $e;
}
// 執行後續代碼
var_dump($o);
echo "\n\n";
// 例子 3
try {
$o = new TestException(TestException::THROW_CUSTOM);
} catch (Exception $e) { // 捕獲異常
echo "Default Exception caught\n", $e;
}
// 執行後續代碼
var_dump($o);
echo "\n\n";
// 例子 4
try {
$o = new TestException();
} catch (Exception $e) { // 沒有異常,被忽略
echo "Default Exception caught\n", $e;
}
// 執行後續代碼
var_dump($o);
echo "\n\n";
?>
12.生成器
生成器允許你在 foreach代碼塊中寫代碼來迭代一組數據而不需要在內存中創建一個數組, 那會使你的內存達到上限,或者會占據可觀的處理時間。相反,你可以寫一個生成器函數,就像一個普通的自定義函數一樣, 和普通函數只返回一次不同的是, 生成器可以根據需要 yield 多次,以便生成需要迭代的值。
<?php
function xrange($start, $limit, $step = 1) {
if ($start < $limit) {
if ($step <= 0) {
throw new LogicException('Step must be +ve');
}
for ($i = $start; $i <= $limit; $i += $step) {
yield $i;
}
} else {
if ($step >= 0) {
throw new LogicException('Step must be -ve');
}
for ($i = $start; $i >= $limit; $i += $step) {
yield $i;
}
}
}
/* Note that both range() and xrange() result in the same
* output below. */
echo 'Single digit odd numbers from range(): ';
foreach (range(1, 9, 2) as $number) {
echo "$number ";
}
echo "\n";
echo 'Single digit odd numbers from xrange(): ';
foreach (xrange(1, 9, 2) as $number) {
echo "$number ";
}
?>
Single digit odd numbers from range(): 1 3 5 7 9 Single digit odd numbers from xrange(): 1 3 5 7 9
The primary advantage of generators is their simplicity. Much less boilerplate code has to be written compared to implementing anIterator class, and the code is generally much more readable. For example, the following function and class are equivalent:
<?php
function getLinesFromFile($fileName) {
if (!$fileHandle = fopen($fileName, 'r')) {
return;
}
while (false !== $line = fgets($fileHandle)) {
yield $line;
}
fclose($fileHandle);
}
// versus...
class LineIterator implements Iterator {
protected $fileHandle;
protected $line;
protected $i;
public function __construct($fileName) {
if (!$this->fileHandle = fopen($fileName, 'r')) {
throw new RuntimeException('Couldn\'t open file "' . $fileName . '"');
}
}
public function rewind() {
fseek($this->fileHandle, 0);
$this->line = fgets($this->fileHandle);
$this->i = 0;
}
public function valid() {
return false !== $this->line;
}
public function current() {
return $this->line;
}
public function key() {
return $this->i;
}
public function next() {
if (false !== $this->line) {
$this->line = fgets($this->fileHandle);
$this->i++;
}
}
public function __destruct() {
fclose($this->fileHandle);
}
}
?>
13.引用
<?php
$a =& $b; //這意味著 $a 和 $b 指向了同一個變量。$a 和 $b 在這裡是完全相同的,這並不是 $a 指向了 $b 或者· //相反,而是 $a 和 $b 指向了同一個地方。
?>
如果具有引用的數組被拷貝,其值不會解除引用。對於數組傳值給函數也是如此。如果對一個未定義的變量進行引用賦值、引用參數傳遞或引用返回,則會自動創建該變量。
<?php
function foo(&$var) { }
foo($a); // $a is "created" and assigned to null
$b = array();
foo($b['b']);
var_dump(array_key_exists('b', $b)); // bool(true)
$c = new StdClass;
foo($c->d);
var_dump(property_exists($c, 'd')); // bool(true)
?>
同樣的語法可以用在函數中,它返回引用,以及用在 new運算符中(PHP 4.0.4 以及以後版本):
<?php
$bar =& new fooclass();
$foo =& find_var($bar);
?>
如果在一個函數內部給一個聲明為 global的變量賦於一個引用,該引用只在函數內部可見。可以通過使用 $GLOBALS 數組避免這一點。在函數內引用全局變量:
<?php
$var1 = "Example variable";
$var2 = "";
function global_references($use_globals){
global $var1, $var2;
if (!$use_globals) {
$var2 =& $var1; // visible only inside the function
} else {
$GLOBALS["var2"] =& $var1; // visible also in global context
}
}
global_references(false);
echo "var2 is set to '$var2'\n"; // var2 is set to ''
global_references(true);
echo "var2 is set to '$var2'\n"; // var2 is set to 'Example variable'
?>
把 global $var; 當成是 $var =& $GLOBALS['var']; 的簡寫。從而將其它引用賦給 $var 只改變了本地變量的引用。
如果在 foreach語句中給一個具有引用的變量賦值,被引用的對象也被改變。
<?php
$ref = 0;
$row =& $ref;
foreach (array(1, 2, 3) as $row) {// do something}
echo $ref; // 3 - last element of the iterated array
?>
引用做的第二件事是用引用傳遞變量。這是通過在函數內建立一個本地變量並且該變量在呼叫范圍內引用了同一個內容來實現的。例如:
<?php
function foo(&$var){
$var++;
}
$a=5;
foo($a);
?>
將使 $a 變成 6。這是因為在 foo 函數中變量 $var 指向了和 $a 指向的同一個內容。更多詳細解釋見引用傳遞。
引用做的第三件事是引用返回。引用不是指針。
可以將一個變量通過引用傳遞給函數,這樣該函數就可以修改其參數的值。
<?php
function foo(&$var){
$var++;
}
$a=5;
foo($a);// $a is 6 here
?>
注意在函數調用時沒有引用符號——只有函數定義中有。光是函數定義就足夠使參數通過引用來正確傳遞了
以下內容可以通過引用傳遞:
變量,例如 foo($a);New 語句,例如 foo(new foobar());從函數中返回的引用
任何其它表達式都不能通過引用傳遞,結果未定義。
<?php
function bar(){ // Note the missing &
$a = 5;
return $a;
}
foo(bar()); // 自 PHP 5.0.5 起導致致命錯誤
foo($a = 5) // 表達式,不是變量
foo(5) // 導致致命錯誤
?>
引用返回用在當想用函數找到引用應該被綁定在哪一個變量上面時。不要用返回引用來增加性能,引擎足夠聰明來自己進行優化。僅在有合理的技術原因時才返回引用!要返回引用,使用此語法:
<?php
class foo {
public $value = 42;
public function &getValue() {
return $this->value;
}
}
$obj = new foo;
$myValue = &$obj->getValue(); // $myValue is a reference to $obj->value, which is 42.
$obj->value = 2;
echo $myValue; // prints the new value of $obj->value, i.e. 2.
?>
本例中 getValue 函數所返回的對象的屬性將被賦值,而不是拷貝,就和沒有用引用語法一樣。和參數傳遞不同,這裡必須在兩個地方都用 &符號——指出返回的是一個引用,而不是通常的一個拷貝,同樣也指出 $myValue是作為引用的綁定,而不是通常的賦值。當 unset 一個引用,只是斷開了變量名和變量內容之間的綁定。這並不意味著變量內容被銷毀了。
<?php
$a = 1;
$b =& $a;
unset($a);
?>
不會 unset $b,只是 $a。引用定位:
global引用:當用 global $var 聲明一個變量時實際上建立了一個到全局變量的引用。也就是說和這樣做是相同的:
<?php
$var =& $GLOBALS["var"]; //這意味著,例如,unset $var 不會 unset 全局變量。
?>
$this:在一個對象的方法中,$this 永遠是調用它的對象的引用。
14.預定義變量
超全局變量 — 超全局變量是在全部作用域中始終可用的內置變量PHP 中的許多預定義變量都是"超全局的",這意味著它們在一個腳本的全部作用域中都可用。在函數或方法中無需執行 global $variable; 就可以訪問它們。這些超全局變量是:
$GLOBALS;$_SERVER;$_GET;$_POST;$_FILES;$_COOKIE;$_SESSION;$_REQUEST;$_ENV默認情況下,所有的超全局變量都是可用的。但是,有一些指令會影響這種可用性。
$GLOBALS — 引用全局作用域中可用的全部變量一個包含了全部變量的全局組合數組。變量的名字就是數組的鍵。
<?php
function test() {
$foo = "local variable";
echo '$foo in global scope: ' . $GLOBALS["foo"] . "\n";//$foo in global scope: Example content
echo '$foo in current scope: ' . $foo . "\n";//$foo in current scope: local variable
}
$foo = "Example content";
test();
?>
"Superglobal"也稱為自動化的全局變量。這就表示其在腳本的所有作用域中都是可用的。不需要在函數或方法中用global $variable; 來訪問它。與所有其他超全局變量不同,$GLOBALS在PHP中總是可用的。
$_SERVER 是一個包含了諸如頭信息(header)、路徑(path)、以及腳本位置(script locations)等等信息的數組。這個數組中的項目由
Web 服務器創建。在 $_SERVER 中,你也許能夠,也許不能夠找到下面的這些元素。列舉:
'PHP_SELF':當前執行腳本的文件名,與 document root 有關。例如,在地址為 http://example.com/test.php/foo.bar 的腳本中使用
$_SERVER['PHP_SELF'] 將得到 /test.php/foo.bar。
'SERVER_ADDR':當前運行腳本所在的服務器的 IP 地址。
'SERVER_NAME':當前運行腳本所在的服務器的主機名。如果腳本運行虛擬主機,該名稱是由那個虛擬主機所設置的值決定。
'SERVER_PROTOCOL':請求頁面時通信協議的名稱和版本。例如,"HTTP/1.0"。
'REQUEST_METHOD':訪問頁面使用的請求方法;例如,"GET", "HEAD","POST","PUT"。
'REQUEST_TIME':請求開始時的時間戳。從 PHP 5.1.0 起可用。
'QUERY_STRING':query string(查詢字符串),如果有的話,通過它進行頁面訪問。
'HTTP_HOST':當前請求頭中 Host: 項的內容,如果存在的話。
'HTTP_REFERER':引導用戶代理到當前頁的前一頁的地址(如果存在)。由 user agent 設置決定。並不是所有的用戶代理都會設置該項,有的還提供了修改 HTTP_REFERER 的功能。簡言之,該值並不可信。
'HTTP_USER_AGENT':當前請求頭中 User-Agent: 項的內容,如果存在的話。該字符串表明了訪問該頁面的用戶代理的信息。
'REMOTE_ADDR':浏覽當前頁面的用戶的 IP 地址。
'REMOTE_HOST':浏覽當前頁面的用戶的主機名。DNS 反向解析不依賴於用戶的 REMOTE_ADDR。
'SERVER_PORT':Web 服務器使用的端口。默認值為 "80"。如果使用 SSL 安全連接,則這個值為用戶設置的 HTTP 端口。
$_GET:通過 URL 參數傳遞給當前腳本的變量的數組。GET 是通過 urldecode() 傳遞的。
$_POST:通過 HTTP POST 方法傳遞給當前腳本的變量的數組。
$_FILES:通過 HTTP POST 方式上傳到當前腳本的項目的數組。
$_REQUEST — HTTP Request 變量,以命令行方式運行時,將不包含 argv 和 argc 信息;它們將存在於 $_SERVER數組。
由於 $_REQUEST 中的變量通過 GET,POST 和 COOKIE 輸入機制傳遞給腳本文件,因此可以被遠程用戶篡改而並不可信。這個數組的項目及其順序依賴於 PHP 的 variables_order 指令的配置。
$_SESSION:當前腳本可用 SESSION 變量的數組。
move_uploaded_file() - 將上傳的文件移動到新位置;import_request_variables() - 將 GET/POST/Cookie 變量導入到全局作用域中;session_start() - 啟動新會話或者重用現有會話;getenv() - 獲取一個環境變量的值;$_ENV:通過環境方式傳遞給當前腳本的變量的數組。這些變量被從 PHP 解析器的運行環境導入到 PHP 的全局命名空間。很多是由支持 PHP 運行的 Shell 提供的,並且不同的系統很可能運行著不同種類的 Shell,所以不可能有一份確定的列表。請查看你的 Shell 文檔來獲取定義的環境變量列表。其他環境變量包含了 CGI 變量,而不管 PHP 是以服務器模塊還是 CGI 處理器的方式運行。
$_COOKIE:通過 HTTP Cookies 方式傳遞給當前腳本的變量的數組。setcookie() - Send a cookie
$php_errormsg — 前一個錯誤信息;$php_errormsg 變量包含由 PHP 生成的最新錯誤信息。這個變量只在錯誤發生的作用域內可用,並且要求 track_errors 配置項是開啟的(默認是關閉的)。如果用戶定義了錯誤處理句柄(set_error_handler())並且返回 FALSE
的時候,$php_errormsg 就會被設置。
<?php
@strpos();
echo $php_errormsg; //Wrong parameter count for strpos()
?>
$HTTP_RAW_POST_DATA — 原生POST數據。$HTTP_RAW_POST_DATA 包含 POST 提交的原始數據。參見 always_populate_raw_post_data一般而言,使用 php://input代替 $HTTP_RAW_POST_DATA。
$http_response_header — HTTP 響應頭:$http_response_header數組與 get_headers() 函數類似。當使用HTTP 包裝器時,$http_response_header 將會被 HTTP 響應頭信息填充。$http_response_header 將被創建於局部作用域中。
<?php
function get_contents() {
file_get_contents("http://example.com");
var_dump($http_response_header);
}
get_contents();
var_dump($http_response_header);
?>
$argc — 傳遞給腳本的參數數目:包含當運行於命令行下時傳遞給當前腳本的參數的數目。腳本的文件名總是作為參數傳遞給當前腳本,因此 $argc 的最小值為 1。這個變量僅在 register_argc_argv 打開時可用。
$argv — 傳遞給腳本的參數數組:包含當運行於命令行下時傳遞給當前腳本的參數的數組。第一個參數總是當前腳本的文件名,因此 $argv[0] 就是腳本文件名。這個變量僅在 register_argc_argv 打開時可用。
Exception是所有異常的基類。類摘要:
Exception { /* 屬性 */ protectedstring$message ; protectedint$code ; protectedstring$file ; protectedint$line ; /* 方法 */ public__construct ([ string$message
= "" [, int$code
= 0 [, Exception$previous
= NULL
]]] )
finalpublicstringgetMessage ( void )
finalpublicExceptiongetPrevious ( void )
finalpublicintgetCode ( void )
finalpublicstringgetFile ( void )
finalpublicintgetLine ( void )
finalpublicarraygetTrace ( void )
finalpublicstringgetTraceAsString ( void )
publicstring__toString ( void )
finalprivatevoid__clone ( void )
}
屬性:message:異常消息內容;code:異常代碼;file:拋出異常的文件名;line:拋出異常在該文件中的行號
Exception::__construct — 異常構造函數
參數:message:拋出的異常消息內容。code:異常代碼。previous:異常鏈中的前一個異常。Exception::getMessage — 獲取異常消息內容
參數:此函數沒有參數。Exception::getPrevious — 返回異常鏈中的前一個異常
參數:Exception::getPrevious — 返回異常鏈中的前一個異常。追蹤異常,並循環打印。<?php
class MyCustomException extends Exception {}
function doStuff() {
try {
throw new InvalidArgumentException("You are doing it wrong!", 112);
} catch(Exception $e) {
throw new MyCustomException("Something happend", 911, $e);
}
}
try {
doStuff();
} catch(Exception $e) {
do {
printf("%s:%d %s (%d) [%s]\n", $e->getFile(), $e->getLine(), $e->getMessage(), $e- >getCode(), get_class($e));
} while($e = $e->getPrevious());
}
?>
以上例程的輸出類似於:
/home/bjori/ex.php:8 Something happend (911) [MyCustomException] /home/bjori/ex.php:6 You are doing it wrong! (112) [InvalidArgumentException]
Exception::getCode — 獲取異常代碼
參數:此函數沒有參數。Exception::getFile — 獲取發生異常的程序文件名稱
參數:此函數沒有參數。Exception::getLine — 獲取發生異常的代碼在文件中的行號
參數:此函數沒有參數。Exception::getTrace — 獲取異常追蹤信息
參數:此函數沒有參數。Exception::getTraceAsString — 獲取字符串類型的異常追蹤信息
參數:此函數沒有參數。Exception::__toString — 將異常對象轉換為字符串
參數:此函數沒有參數。Exception::__clone — 異常克隆
參數:此函數沒有參數。沒有返回值,異常被不允許克隆。ErrorException::__construct — 異常構造函數
參數:message:拋出的異常消息內容。code:異常代碼。severity:異常的嚴重級別。filename:拋出異常所在的文件名。lineno:拋出異常所在的行號。previous:異常鏈中的前一個異常。ErrorException::getSeverity — 獲取異常的嚴重程度
參數:此函數沒有參數。<?php
try {
throw new ErrorException("Exception message", 0, 75);
} catch(ErrorException $e) {
echo "This exception severity is: " . $e->getSeverity();
}
?>
16.預定義接口
Traversable(遍歷)接口:
檢測一個類是否可以使用 foreach 進行遍歷的接口。無法被單獨實現的基本抽象接口。相反它必須由 IteratorAggregate 或 Iterator 接口實現。實現此接口的內建類可以使用 foreach 進行遍歷而無需實現 IteratorAggregate 或 Iterator 接口。這是一個無法在 PHP 腳本中實現的內部引擎接口。IteratorAggregate 或 Iterator 接口可以用來代替它。
Traversable { } 這個接口沒有任何方法,它的作用僅僅是作為所有可遍歷類的基本接口。 Iterator(迭代器)接口:可在內部迭代自己的外部迭代器或類的接口。
IteratorextendsTraversable { /* 方法 */ abstractpublicmixedcurrent ( void ) abstractpublicscalarkey ( void ) abstractpublicvoidnext ( void ) abstractpublicvoidrewind ( void ) abstractpublicbooleanvalid ( void ) }Iterator::current — 返回當前元素:沒有參數,可返回任何類型。
Iterator::key — 返回當前元素的鍵:沒有參數,成功返回標量,失敗則返回null。
Iterator::next — 向前移動到下一個元素:沒有參數,任何返回都將被忽略。此方法在 foreach 循環之後被調用。
Iterator::rewind — 返回到迭代器的第一個元素:當開始一個 foreach 循環時,這是第一個被調用的方法。它將不會在 foreach 循環之後被調用。沒有參數,任何返回都將被忽略。
Iterator::valid — 檢查當前位置是否有效:此方法在 Iterator::rewind() 和 Iterator::next() 方法之後被調用以此用來檢查當前位置是否有效。沒有參數,返回將被轉換為布爾型。成功時返回 TRUE
, 或者在失敗時返回 FALSE
。
IteratorAggregate::getIterator — 獲取一個外部迭代器:沒有參數,實現了 Iterator 或 Traversable 接口的類的一個實例。
ArrayAccess(數組式訪問)接口:提供像訪問數組一樣訪問對象的能力的接口。
ArrayAccess { /* 方法 */ abstractpublicbooleanoffsetExists ( mixed$offset
)
abstractpublicmixedoffsetGet ( mixed$offset
)
abstractpublicvoidoffsetSet ( mixed$offset
, mixed$value
)
abstractpublicvoidoffsetUnset ( mixed$offset
)
}
ArrayAccess::offsetExists — 檢查一個偏移位置是否存在:對一個實現了 ArrayAccess 接口的對象使用 isset() 或 empty() 時,此方法將執行。當使用 empty() 並且僅當 ArrayAccess::offsetExists() 返回 TRUE
時,ArrayAccess::offsetGet() 將被調用以檢查是為否空。參數:offset 需要檢查的偏移位置。成功時返回 TRUE
, 或者在失敗時返回 FALSE
。如果一個非布爾型返回值被返回,將被轉換為布爾型。
<?php
class obj implements arrayaccess {
public function offsetSet($offset, $value) {
var_dump(__METHOD__);
}
public function offsetExists($var) {
var_dump(__METHOD__);
if ($var == "foobar") {
return true;
}
return false;
}
public function offsetUnset($var) {
var_dump(__METHOD__);
}
public function offsetGet($var) {
var_dump(__METHOD__);
return "value";
}
}
$obj = new obj;
echo "Runs obj::offsetExists()\n";
var_dump(isset($obj["foobar"]));
echo "\nRuns obj::offsetExists() and obj::offsetGet()\n";
var_dump(empty($obj["foobar"]));
echo "\nRuns obj::offsetExists(), *not* obj:offsetGet() as there is nothing to get\n";
var_dump(empty($obj["foobaz"]));
?>
以上例程的輸出類似於:
Runs obj::offsetExists() string(17) "obj::offsetExists" bool(true) Runs obj::offsetExists() and obj::offsetGet() string(17) "obj::offsetExists" string(14) "obj::offsetGet" bool(false) Runs obj::offsetExists(), *not* obj:offsetGet() as there is nothing to get string(17) "obj::offsetExists" bool(true)
ArrayAccess::offsetGet — 獲取一個偏移位置的值:當檢查一個偏移位置是否為 empty() 時,此方法被執行。
參數:offset 需要獲取的偏移位置。返回值:可返回任何類型。ArrayAccess::offsetSet — 設置一個偏移位置的值:參數:offset 待設置的偏移位置。value 需要設置的值。沒有返回值。
如果另一個值不可用,那麼 offset
參數將被設置為 NULL。
ArrayAccess::offsetUnset — 復位一個偏移位置的值:當使用 (unset) 進行類型轉換時,該方法不會被調用。
參數:offset
待復位的偏移位置。沒有返回值。
序列化接口:
Serializable::serialize — 對象的字符串表示。這個方法擔當著對象析構器的角色。在此方法之後,__destruct() 方法將不會被調用。此函數沒有參數,返回值:返回對象的字符串表示或者 NULL
。
Serializable::unserialize — 構造對象。這個方法擔當著對象構造器的角色。在此方法之後,__construct() 將不會被調用。參數:serialized 對象的字符串表示。
Closure::__construct — 用於禁止實例化的構造函數。這個方法僅用於禁止實例化一個 Closure 類的對象。這個類的對象的創建方法寫在 匿名函數 頁。此函數沒有參數,沒有返回值。
Closure::bind — 復制一個閉包,綁定指定的$this對象和類作用域。這個方法是 Closure::bindTo() 的靜態版本。
參數:closure 需要綁定的匿名函數。newthis 需要綁定到匿名函數的對象,或者
NULL
創建未綁定的閉包。newscope 想要綁定給閉包的類作用域,或者 'static' 表示不改變。如果傳入一個對象,則使用這個對象的類型名。 類作用域用來決定在閉包中 $this 對象的 私有、保護方法 的可見性。返回一個新的 Closure 對象 或者在失敗時返回 FALSE
<?php
class A {
private static $sfoo = 1;
private $ifoo = 2;
}
$cl1 = static function() {
return A::$sfoo;
};
$cl2 = function() {
return $this->ifoo;
};
$bcl1 = Closure::bind($cl1, null, 'A');
$bcl2 = Closure::bind($cl2, new A(), 'A');
echo $bcl1(), "\n"; //1
echo $bcl2(), "\n"; //2
?>
Closure::bindTo — 復制當前閉包對象,綁定指定的$this對象和類作用域。創建並返回一個 匿名函數, 它與當前對象的函數體相同、綁定了同樣變量,但可以綁定不同的對象,也可以綁定新的類作用域。"綁定的對象"決定了函數體中的 $this的取值,"類作用域"代表一個類型、決定在這個匿名函數中能夠調用哪些 私有 和 保護 的方法。 也就是說,此時 $this 可以調用的方法,與 newscope
類的成員函數是相同的。靜態閉包不能有綁定的對象( newthis
參數的值應該設為 NULL
)不過仍然可以用 bubdTo 方法來改變它們的類作用域。如果你只是想要復制一個匿名函數,可以用 cloning 代替。
NULL
來取消綁定。newscope 關聯到匿名函數的類作用域,或者 'static' 保持當前狀態。如果是一個對象,則使用這個對象的類型為心得類作用域。 這會決定綁定的對象的 保護、私有成員 方法的可見性。返回值:返回新創建的 Closure 對象 或者在失敗時返回 FALSE
<?php
class A {
function __construct($val) {
$this->val = $val;
}
function getClosure() {
//returns closure bound to this object and scope
return function() { return $this->val; };
}
}
$ob1 = new A(1);
$ob2 = new A(2);
$cl = $ob1->getClosure();
echo $cl(), "\n"; //1
$cl = $cl->bindTo($ob2);
echo $cl(), "\n"; //2
?>
17.上下文選項和參數
套接字上下文選項可用於所有工作在套接字上的封裝協議,像 tcp, http 和 ftp.
<?php
// connect to the internet using the '192.168.0.100' IP
$opts = array(
'socket' => array(
'bindto' => '192.168.0.100:0',
),
);
// connect to the internet using the '192.168.0.100' IP and port '7000'
$opts = array(
'socket' => array(
'bindto' => '192.168.0.100:7000',
),
);
// connect to the internet using port '7000'
$opts = array(
'socket' => array(
'bindto' => '0:7000',
),
);
// create the context...
$context = stream_context_create($opts);
// ...and use it to fetch the data
echo file_get_contents('http://www.example.com', false, $context);
?>
HTTP context 選項 — HTTP context 的選項列表。提供給 http:// 和 https:// 傳輸協議的 context 選項。 transports.可選項:
method
string 遠程服務器支持的 GET
,POST
或其它 HTTP 方法。默認值是 GET
。header
string 請求期間發送的額外 header 。在此選項的值將覆蓋其他值 (諸如 User-agent:, Host: 和 Authentication:)。user_agent
string 要發送的 header User-Agent: 的值。如果在上面的 header context 選項中沒有指定 user-agent,此值將被使用。默認使用 php.ini中設置的 user_agent。content
string 在 header 後面要發送的額外數據。通常使用POST或PUT請求。proxy
string URI 指定的代理服務器的地址。(e.g. tcp://proxy.example.com:5100).request_fulluri
boolean 當設置為 TRUE
時,在構建請求時將使用整個 URI 。(i.e. GET http://www.example.com/path/to/file.html HTTP/1.0)。 雖然這是一個非標准的請求格式,但某些代理服務器需要它。默認值是 FALSE
.follow_location
integer 跟隨 Location header 的重定向。設置為 0 以禁用。默認值是 1。max_redirects
integer 跟隨重定向的最大次數。值為 1 或更少則意味不跟隨重定向。默認值是 20。protocol_version
float HTTP 協議版本。默認值是 1.0。PHP 5.3.0 以前的版本沒有實現分塊傳輸解碼。 如果此值設置為 1.1 ,與 1.1 的兼容將是你的責任。timeout
float 讀取超時時間,單位為秒(s),用 float 指定(e.g. 10.5)。默認使用 php.ini 中設置的 default_socket_timeout。ignore_errors
boolean 即使是故障狀態碼依然獲取內容。默認值為 FALSE
.
FTP context options — FTP context option listing
SSL 上下文選項 — SSL 上下文選項清單。ssl:// 和 tls://傳輸協議上下文選項清單。可選項:好多。
CURL context options — CURL 上下文選項列表。CURL 上下文選項在 CURL 擴展被編譯(通過 --with-curlwrappers configure選項)時可用。可選項:
method
string GET
,POST
,或者其他遠程服務器支持的 HTTP 方法。默認為 GET
.header
string 額外的請求標頭。這個值會覆蓋通過其他選項設定的值(如: User-agent:,Host:, ,Authentication:)。user_agent
string 設置請求時 User-Agent 標頭的值。默認為 php.ini 中的 user_agent設定。content
string 在頭部之後發送的額外數據。這個選項在 GET
和 HEAD
請求中不使用。proxy
string URI,用於指定代理服務器的地址(例如 tcp://proxy.example.com:5100)。max_redirects
integer 最大重定向次數。1 或者更小則代表不會跟隨重定向。默認為 20.curl_verify_ssl_host
boolean校驗服務器。默認為 FALSE。
這個選項在 HTTP 和 FTP 協議中均可使用。curl_verify_ssl_peer
boolean 要求對使用的SSL證書進行校驗。默認為 FALSE。
這個選項在 HTTP 和 FTP 協議中均可使用。獲取一個頁面,並以POST發送數據:
<?php
$postdata = http_build_query(
array(
'var1' => 'some content',
'var2' => 'doh'
)
);
$opts = array('http' =>
array(
'method' => 'POST',
'header' => 'Content-type: application/x-www-form-urlencoded',
'content' => $postdata
)
);
$context = stream_context_create($opts);
$result = file_get_contents('http://example.com/submit.php', false, $context);
?>
Phar 上下文(context)選項 — Phar 上下文(context)選項列表。phar:// 封裝(wrapper)的上下文(context)選項。可選項:compress
int Phar compression constants 中的一個。metadata
mixed Phar 元數據(metadata)。查看 Phar::setMetadata()。
Context 參數 — Context 參數列表。這些參數(parameters)可以設置為由函數 stream_context_set_params() 返回的 context。參數:notification
callable 當一個流(stream)上發生事件時,callable 將被調用。
file:// — 訪問本地文件系統。文件系統 是 PHP 使用的默認封裝協議,展現了本地文件系統。 當指定了一個相對路徑(不以/、\、\\或 Windows 盤符開頭的路徑)提供的路徑將基於當前的工作目錄。 在很多情況下是腳本所在的目錄,除非被修改了。 使用 CLI 的時候,目錄默認是腳本被調用時所在的目錄。
在某些函數裡,例如 fopen() 和 file_get_contents(), include_path 會可選地搜索,也作為相對的路徑。
http:// -- https:// — 訪問 HTTP(s) 網址。允許通過 HTTP 1.0 的 GET方法,以只讀訪問文件或資源。 HTTP 請求會附帶一個 Host: 頭,用於兼容基於域名的虛擬主機。 如果在你的 php.ini 文件中或字節流上下文(context)配置了 user_agent 字符串,它也會被包含在請求之中。數據流允許讀取資源的 body,而 headers 則儲存在了 $http_response_header 變量裡。
如果需要知道文檔資源來自哪個 URL(經過所有重定向的處理後), 需要處理數據流返回的系列響應報頭(response headers)。
ftp:// -- ftps:// — 訪問 FTP(s) URLs。允許通過 FTP 讀取存在的文件,以及創建新文件。 如果服務器不支持被動(passive)模式的 FTP,連接會失敗。
打開文件後你既可以讀也可以寫,但是不能同時進行。 當遠程文件已經存在於 ftp 服務器上,如果嘗試打開並寫入文件的時候, 未指定上下文(context)選項 overwrite,連接會失敗。 如果要通過 FTP 覆蓋存在的文件, 指定上下文(context)的 overwrite 選項來打開、寫入。 另外可使用 FTP 擴展來代替。如果你設置了 php.ini 中的 from 指令, 這個值會作為匿名(anonymous)ftp 的密碼。
overwrite
後已存在的文件)
允許添加
No
Yes
允許同時讀和寫
No
No
支持 stat()
No
自 5.0.0 起:僅僅 filesize()、 filetype()、 file_exists()、 is_file() 和 is_dir()。 自 PHP 5.1.0 起: filemtime()。
支持 unlink()
No
Yes
支持 rename()
No
Yes
支持 mkdir()
No
Yes
支持 rmdir()
No
Yes
php:// — 訪問各個輸入/輸出流(I/O streams)。PHP 提供了一些雜項輸入/輸出(IO)流,允許訪問 PHP 的輸入輸出流、標准輸入輸出和錯誤描述符, 內存中、磁盤備份的臨時文件流以及可以操作其他讀取寫入文件資源的過濾器。
php://stdin、php://stdout 和 php://stderr 允許直接訪問 PHP 進程相應的輸入或者輸出流。 數據流引用了復制的文件描述符,所以如果你打開 php://stdin 並在之後關了它, 僅是關閉了復制品,真正被引用的 STDIN
並不受影響。 注意 PHP 在這方面的行為有很多 BUG 直到 PHP 5.2.1。 推薦你簡單使用常量 STDIN
、 STDOUT
和 STDERR
來代替手工打開這些封裝器。
php://stdin 是只讀的, php://stdout 和 php://stderr 是只寫的。
php://input 是個可以訪問請求的原始數據的只讀流。 POST 請求的情況下,最好使用 php://input 來代替 $HTTP_RAW_POST_DATA,因為它不依賴於特定的 php.ini 指令。 而且,這樣的情況下 $HTTP_RAW_POST_DATA 默認沒有填充, 比激活 always_populate_raw_post_data潛在需要更少的內存。 enctype="multipart/form-data" 的時候 php://input 是無效的。
php://output 是一個只寫的數據流, 允許你以 print 和 echo 一樣的方式 寫入到輸出緩沖區。
php://fd 允許直接訪問指定的文件描述符。 例如 php://fd/3 引用了文件描述符 3。
php://memory 和 php://temp 是一個類似文件 包裝器的數據流,允許讀寫臨時數據。 兩者的唯一區別是 php://memory 總是把數據儲存在內存中, 而 php://temp 會在內存量達到預定義的限制後(默認是 2MB)存入臨時文件中。 臨時文件位置的決定和 sys_get_temp_dir() 的方式一致。php://temp 的內存限制可通過添加 /maxmemory:NN來控制,NN 是以字節為單位、保留在內存的最大數據量,超過則使用臨時文件。
php://filter 是一種元封裝器, 設計用於數據流打開時的篩選過濾應用。 這對於一體式(all-in-one)的文件函數非常有用,類似 readfile()、 file() 和 file_get_contents(), 在數據流內容讀取之前沒有機會應用其他過濾器。php://filter 目標使用以下的參數作為它路徑的一部分。 復合過濾鏈能夠在一個路徑上指定。
zlib:// -- bzip2:// -- zip:// — 壓縮流。zlib: PHP 4.0.4 - PHP 4.2.3(僅支持帶 fopencookie 的系統)
compress.zlib:// 和 compress.bzip2:// PHP 4.3.0 及以上
zlib: 的功能類似 gzopen(),但是 其數據流還能被 fread() 和其他文件系統函數使用。 自 PHP 4.3.0 後這個不建議被使用,因為會和其他帶":"字符的文件名混淆; 請使用 compress.zlib:// 作為替代。
compress.zlib://、 compress.bzip2://和 gzopen()、bzopen()是相等的。並且可以在不支持 fopencookie 的系統中使用。
ZIP 擴展 注冊了 zip: 封裝協議。可選項
data:// — 數據(RFC 2397)。用法:data://text/plain;base64,
打印 data:// 的內容:
<?php
// 打印 "I love PHP"
echo file_get_contents('data://text/plain;base64,SSBsb3ZlIFBIUAo=');
?>
獲取媒體類型:
<?php
$fp = fopen('data://text/plain;base64,', 'r');
$meta = stream_get_meta_data($fp);
echo $meta['mediatype']; // 打印 "text/plain"
?>
glob:// — 查找匹配的文件路徑模式。用法:glob://
<?php
// 循環 ext/spl/examples/ 目錄裡所有 *.php 文件
// 並打印文件名和文件尺寸
$it = new DirectoryIterator("glob://ext/spl/examples/*.php");
foreach($it as $f) {
printf("%s: %.1FK\n", $f->getFilename(), $f->getSize()/1024);
}
?>
tree.php: 1.0K findregex.php: 0.6K findfile.php: 0.7K dba_dump.php: 0.9K nocvsdir.php: 1.1K phar_from_dir.php: 1.0K ini_groups.php: 0.9K directorytree.php: 0.9K dba_array.php: 1.1K class_tree.php: 1.8K
phar:// — PHP 歸檔。用法:phar://
ssh2:// — Secure Shell 2。
rar:// — RAR。
ogg:// — 音頻流。
expect:// — 處理交互式的流。
=================================================================================================安全!!!