值得注意的是,由 yannick at gmail 定義的介面不應該總是透過串流包裝器類別來實作,因為如果類別不需要使用某些方法,則不應該實作它們(根據手冊)。
具體來說,如果包裝器不需要 mkdir、rename、rmdir 和 unlink 方法,則「不應定義」這些方法。如此一來,才不會傳回不適當的錯誤訊息。
如果實作了介面,就沒有不實作這些方法的彈性。
我不是想咬文嚼字,但这對我來說很有用。
(PHP 4 >= 4.3.2, PHP 5, PHP 7, PHP 8)
允許您實作自己的協定處理程式和串流,以便與所有其他檔案系統函式(例如 fopen()、fread() 等)一起使用。
注意:
這*不是*一個真正的類別,只是一個定義自己協定的類別的原型。
注意:
以與此處描述不同的方式實作這些方法可能會導致未定義的行為。
一旦串流函式嘗試存取與其關聯的協定,就會初始化此類別的實例。
目前的 脈絡 (context),如果沒有脈絡傳遞給呼叫者函數,則為 null
。
使用 stream_context_get_options() 來解析脈絡。
注意:
此屬性*必須*為公開,以便 PHP 可以使用實際的脈絡資源來填充它。
值得注意的是,由 yannick at gmail 定義的介面不應該總是透過串流包裝器類別來實作,因為如果類別不需要使用某些方法,則不應該實作它們(根據手冊)。
具體來說,如果包裝器不需要 mkdir、rename、rmdir 和 unlink 方法,則「不應定義」這些方法。如此一來,才不會傳回不適當的錯誤訊息。
如果實作了介面,就沒有不實作這些方法的彈性。
我不是想咬文嚼字,但这對我來說很有用。
這些方法不是必需的,您可以只實作其中一部分:例如目錄、檔案等等。
例如,「glob://」支援最少的語法,glob() 功能更強大,您可以替換/擴充原生包裝器:在表格 https://php.dev.org.tw/manual/ru/wrappers.glob 中查看選項,您只需要使用 'dir_...dir' 方法建立包裝器。更多資訊請參閱 https://php.dev.org.tw/manual/en/class.globiterator.php#125220
這是一個非常簡單的串流包裝器,它會在讀取時呼叫您的回呼函式。
<?php
class CallbackUrl
{
const WRAPPER_NAME = 'callback';
public $context;
private $_cb;
private $_eof = false;
private static $_isRegistered = false;
public static function getContext($cb)
{
if (!self::$_isRegistered) {
stream_wrapper_register(self::WRAPPER_NAME, get_class());
self::$_isRegistered = true;
}
if (!is_callable($cb)) return false;
return stream_context_create(array(self::WRAPPER_NAME => array('cb' => $cb)));
}
public function stream_open($path, $mode, $options, &$opened_path)
{
if (!preg_match('/^r[bt]?$/', $mode) || !$this->context) return false;
$opt = stream_context_get_options($this->context);
if (!is_array($opt[self::WRAPPER_NAME]) ||
!isset($opt[self::WRAPPER_NAME]['cb']) ||
!is_callable($opt[self::WRAPPER_NAME]['cb'])) return false;
$this->_cb = $opt[self::WRAPPER_NAME]['cb'];
return true;
}
public function stream_read($count)
{
if ($this->_eof || !$count) return '';
if (($s = call_user_func($this->_cb, $count)) == '') $this->_eof = true;
return $s;
}
public function stream_eof()
{
return $this->_eof;
}
}
class Test {
private $_s;
public function __construct($s)
{
$this->_s = $s;
}
public function read($count) {
return fread($this->_s, $count);
}
}
$t = new Test(fopen('/etc/services', 'r'));
$fd = fopen('callback://', 'r', false, CallbackUrl::getContext(array($t, 'read')));
while(($buf = fread($fd, 128)) != '') {
print $buf;
}
?>
包裝器的 PHP 介面
<?php
interface WrapperInterface
{
/**
* resource context
*
* @var resource
*/
//public $context;
/**
* constructor
*
*/
public function __construct();
/**
*
*
* @return bool
*/
public function dir_closedir();
/**
* Enter description here...
*
* @param string $path
* @param int $options
* @return bool
*/
public function dir_opendir($path , $options);
/**
* Enter description here...
*
* @return string
*/
public function dir_readdir();
/**
* Enter description here...
*
* @return bool
*/
public function dir_rewinddir();
/**
* Enter description here...
*
* @param string $path
* @param int $mode
* @param int $options
* @return bool
*/
public function mkdir($path , $mode , $options);
/**
* Enter description here...
*
* @param string $path_from
* @param string $path_to
* @return bool
*/
public function rename($path_from , $path_to);
/**
* Enter description here...
*
* @param string $path
* @param int $options
* @return bool
*/
public function rmdir($path , $options);
/**
* Enter description here...
*
* @param int $cast_as
* @return resource
*/
public function stream_cast($cast_as);
/**
* Enter description here...
*
*/
public function stream_close();
/**
* Enter description here...
*
* @return bool
*/
public function stream_eof();
/**
* Enter description here...
*
* @return bool
*/
public function stream_flush();
/**
* Enter description here...
*
* @param mode $operation
* @return bool
*/
public function stream_lock($operation);
/**
* Enter description here...
*
* @param string $path
* @param string $mode
* @param int $options
* @param string &$opened_path
* @return bool
*/
public function stream_open($path , $mode , $options , &$opened_path);
/**
* Enter description here...
*
* @param int $count
* @return string
*/
public function stream_read($count);
/**
* Enter description here...
*
* @param int $offset
* @param int $whence = SEEK_SET
* @return bool
*/
public function stream_seek($offset , $whence = SEEK_SET);
/**
* Enter description here...
*
* @param int $option
* @param int $arg1
* @param int $arg2
* @return bool
*/
public function stream_set_option($option , $arg1 , $arg2);
/**
* Enter description here...
*
* @return array
*/
public function stream_stat();
/**
* Enter description here...
*
* @return int
*/
public function stream_tell();
/**
* Enter description here...
*
* @param string $data
* @return int
*/
public function stream_write($data);
/**
* Enter description here...
*
* @param string $path
* @return bool
*/
public function unlink($path);
/**
* Enter description here...
*
* @param string $path
* @param int $flags
* @return array
*/
public function url_stat($path , $flags);
}
?>