扩展:PHP预定义接口
Closure
Closure代表匿名函数类,我们所使用的匿名函数是Closure的一个实例,高频使用静态方法bind与bindTo实现匿名函数与实例或类的绑定
final class Closure function bindTo($newthis, $newscope = ‘static’) { }
class Demo
{
private static $static_attribute = 'static_attribute_init';
public $general_attribute = '$general_attribute_init';
public function show_message(){
echo '$static_attribute now is '.self::$static_attribute."\n";
echo '$general_attribute now is '.$this->general_attribute."\n";
}
}
$callback = function(){
self::$static_attribute = 'static_attribute_change';
$this->general_attribute = 'general_attribute_change';
};
$demo = new Demo;
$func = $callback->bindTo($demo,Demo::class);//返回绑定的匿名函数
$func();
$demo->show_message();
输出:
$static_attribute now is static_attribute_change
$general_attribute now is general_attribute_change
bindTo函数的第一个参数是将匿名函数绑定到一个实例,默认为null,当前匿名函数使用到this关键字,顾需要绑定到实例,
bindTo函数的第二个参数是声明匿名函数的作用域,默认为static,当前匿名函数使用到self关键字,顾需要绑定到Demo类作用域,
在绑定实例后如果要更改private属性,则需要声明作用域
final class Closure static function bind(Closure $closure, $newthis, $newscope = ‘static’) { }
使用静态方法调用实现匿名函数绑定
ArrayAccess
提供数组式访问对象接口,实现方式依据继承接口的类自定义,接口摘要
ArrayAccess {
/* 方法 */
abstract public offsetExists ( mixed $offset ) : boolean
abstract public offsetGet ( mixed $offset ) : mixed
abstract public offsetSet ( mixed $offset , mixed $value ) : void
abstract public offsetUnset ( mixed $offset ) : void
}
class Container implements ArrayAccess
{
private $data = [];
//$container[$offset] = $value;
public function offsetSet($offset, $value){
if(is_null($offset)){
$this->data[] = $value;
}else{
$this->data[$offset] = $value;
}
}
//isset($container[$offset]);
public function offsetExists($offset){
return isset($this->data[$offset]) ?:false;
}
//unset($container[$offset]);
public function offsetUnset($offset){
if(isset($this->data[$offset])){
unset($this->data[$offset]);
}
}
//$container[$offset];
public function offsetGet($offset){
if(isset($this->data[$offset])){
return $this->data[$offset];
}
return null;
}
}
$container = new Container();
Traversable
检验一个类是否可以被foreach遍历接口,必须由IteratorAggregate或Iterator接口实现
$checkout = $obj instanceof Traversable;//仅对继承了Traversable接口的实例返回true,对由数组临时转换的对象同样返回false
Iterator
迭代器接口
Iterator extends Traversable {
/* 方法 */
abstract public current ( void ) : mixed
abstract public key ( void ) : scalar
abstract public next ( void ) : void
abstract public rewind ( void ) : void
abstract public valid ( void ) : bool
}
class Implementation_Iterator implements Iterator
{
private $index = 0;
private $list = [
'first','second','third'
];
public function __construct(){
$this->index = 0;
}
public function rewind(){
echo __FUNCTION__."() ### ";
$this->index = 0;
}
public function current(){
echo __FUNCTION__."() ### ";
return $this->list[$this->index];
}
public function key(){
echo __FUNCTION__."();\n";
return $this->index;
}
public function next(){
echo __FUNCTION__."() ### ";
$this->index++;
}
public function valid(){
echo __FUNCTION__."() ### ";
return isset($this->list[$this->index]);
}
}
$implementation_Iterator = new Implementation_Iterator;
foreach($implementation_Iterator as $key => $value){
echo $key."\n".$value."\n";
}
foreach()触发迭代器执行相关函数,执行结果如下:
rewind() ### valid() ### current() ### key();
0
first
next() ### valid() ### current() ### key();
1
second
next() ### valid() ### current() ### key();
2
third
next() ### valid() ###
IteratorAggregate
聚合是迭代器
IteratorAggregate extends Traversable {
/* 方法 */
abstract public getIterator ( void ) : Traversable
}
getIterator()返回实现了Iterator或Traversable 接口的类的一个实例。也就是说可以返回一个聚合迭代器,类似递归的方式,但最终一个聚合迭代器一定是返回Iterator迭代器;
<?php
class Implementation_IteratorAggregate implements IteratorAggregate
{
public $username = "artisan";
public $action = "Implementation IteratorAggregate";
public function getIterator(){
return new ArrayIterator($this);
}
}
$implementation_iteratorAggregate = new Implementation_IteratorAggregate;
foreach($implementation_iteratorAggregate as $key => $value){
echo 'key : '.$key.' --- value : '.$value."\n";
}
?>
getIterator()返回的实例是php标准库(SPL)中实现的迭代器;
在ArrayIterator类继承Iterator,实现rewind()、vaild()、current()、next()、key()等方法;
foreach()的执行过程中依旧是按照顺序执行Iterator的相关方法,执行结果如下:
key : username — value : artisan
key : action — value : Implementation IteratorAggregate
Serializable
自定义序列化接口
Serializable {
/* 方法 */
abstract public serialize ( void ) : string
abstract public unserialize ( string $serialized ) : mixed
}
class Implementation_Serializable implements Serializable
{
private $data;
public function __construct()
{
$this->data = 'private data';
}
public function serialize(){
return serialize($this->data);
}
public function unserialize($data){
$this->data = unserialize($data);
}
public function getData(){
return $this->data;
}
}
$implementation_serializable = new Implementation_Serializable;
$ser = serialize($implementation_serializable);
$new_implementation_serializable = unserialize($ser);
echo $new_implementation_serializable->getData();
自定义serialize()与unserialize()的动作
Generator
Generator实现了Iterator,即核心函数依旧是rewind->valid->current->key->next…,但generator不可以被继承,php应用程序中使用关键字yield调用Generator
Generator implements Iterator {
/* 方法 */
public current ( void ) : mixed
public key ( void ) : mixed
public next ( void ) : void
public rewind ( void ) : void
public send ( mixed $value ) : mixed
public throw ( Exception $exception ) : void
public valid ( void ) : bool
public __wakeup ( void ) : void
}
功能简介
function fib($n)
{
$cur = 1;
$prev = 0;
for ($i = 0; $i < $n; $i++) {
yield $cur;
$temp = $cur;
$cur = $prev + $cur;
$prev = $temp;
}
}
//函数没有返回值,但是$fibs是有数据的
$fibs = fib(9);
var_dump($fibs instanceof Generator);
foreach($fibs as $fib){
echo '---' .$fib;
}
输出
bool(true)
—1---1—2---3—5---8—13—21—34
应用场景:节省内存,用时间换空间
$start_time = microtime(true);
function xrange($num = 100000){
for($i = 0 ; $i < $num ; ++ $i){
yield $i;
}
}
$generator = xrange();
echo 'memory:' . memory_get_usage() . ' time:' . (microtime(true) - $start_time);
memory:391216 time:1.5974044799805E-5%
$start_time = microtime(true);
function xrange2($num = 100000){
$arr = [];
for ($i=0; $i <$num ; ++$i) {
array_push($arr , $i);
}
return $arr;
}
$arr = xrange2();
echo 'memory:' . memory_get_usage() . ' time:' . (microtime(true) - $start_time);
memory:4589376 time:0.0042829513549805
呼~~~:扩展知识到此结束,LoadConfiguration实例的实现过程中使用到了Iterator预定义借口
实现LoadConfiguration
bootstrap()
//class Iluminate\Foundation\Bootstrap\LoadConfiguration
public function bootstrap(Application $app)
{
$items = [];
//校验是否存在缓存配置文件
if (file_exists($cached = $app->getCachedConfigPath())) {
$items = require $cached;
$loadedFromCache = true;
}
//创建$config实例并存储在容器中
$app->instance('config', $config = new Repository($items));
//不存在缓存配置文件到时候加载配置文件
if (! isset($loadedFromCache)) {
$this->loadConfigurationFiles($app, $config);
}
//检测开发环境
$app->detectEnvironment(function () use ($config) {
return $config->get('app.env', 'production');
});
//设置时区
date_default_timezone_set($config->get('app.timezone', 'UTC'));
//设置编码字符集
mb_internal_encoding('UTF-8');
}
上述的核心方法是loadConfigurationFiles()
//class Iluminate\Foundation\Bootstrap\LoadConfiguration
protected function loadConfigurationFiles(Application $app, RepositoryContract $repository)
{
//获取config目录下的文件名称组成的数组
$files = $this->getConfigurationFiles($app);
//将config目录下的文件名即文件内容存储在$config内
foreach ($files as $key => $path) {
$repository->set($key, require $path);
}
}
getConfigurationFiles()使用了IteratorAggregate和SPL中的Iterator
protected function getConfigurationFiles(Application $app)
{
$files = [];
$configPath = realpath($app->configPath());
//Finder继承了IteratorAggregate
foreach (Finder::create()->files()->name('*.php')->in($configPath) as $file) {
$directory = $this->getNestedDirectory($file, $configPath);
$files[$directory.basename($file->getRealPath(), '.php')] = $file->getRealPath();
}
ksort($files, SORT_NATURAL);
return $files;
}
Finder::create()->files()->name(’*.php’)->in($configPath)
//class Symfony\Component\Finder\Finder
public static function create()
{
//创建并返回实例
return new static();
}
public function files()
{
$this->mode = Iterator\FileTypeFilterIterator::ONLY_FILES;
return $this;
}
public function name($pattern)
{
$this->names[] = $pattern;
return $this;
}
public function in($dirs)
{
$resolvedDirs = [];
foreach ((array) $dirs as $dir) {
if (is_dir($dir)) {
//$this->normalizeDir($dir):/usr/local/var/www/auth/config
$resolvedDirs[] = $this->normalizeDir($dir);
}
}
//$this->dirs = [];
$this->dirs = array_merge($this->dirs, $resolvedDirs);
return $this;
}
上述Finder的方法使用链式操作设定相关参数,在foreach的时候出发getIterator()
//class Symfony\Component\Finder\Finder
public function getIterator()
{
...
return $this->searchInDirectory($this->dirs[0]);
...
}
private function searchInDirectory($dir)
{
$exclude = $this->exclude;//[]
$notPaths = $this->notPaths;//[]
if (static::IGNORE_VCS_FILES === (static::IGNORE_VCS_FILES & $this->ignore)) {
$exclude = array_merge($exclude, self::$vcsPatterns);//$exclude = self::$vcsPatterns
}
if (static::IGNORE_DOT_FILES === (static::IGNORE_DOT_FILES & $this->ignore)) {
$notPaths[] = '#(^|/)\..+(/|$)#';//$notPaths = "#(^|/)\..+(/|$)#";
}
...
$flags = \RecursiveDirectoryIterator::SKIP_DOTS;
...
//创建自定义继承了\RecursiveDirectoryIterator的iterator实例,细节请查看php官网SPL定义的Iterator
$iterator = new Iterator\RecursiveDirectoryIterator($dir, $flags, $this->ignoreUnreadableDirs);
//使用SPL过滤目录iterator,过滤.git等目录
if ($exclude) {
$iterator = new Iterator\ExcludeDirectoryFilterIterator($iterator, $exclude);
}
//使用SPL递归迭代iterator
$iterator = new \RecursiveIteratorIterator($iterator, \RecursiveIteratorIterator::SELF_FIRST);
...
//使用SPL文件类型过滤iterator
if ($this->mode) {
$iterator = new Iterator\FileTypeFilterIterator($iterator, $this->mode);
}
//使用SPL文件名称过滤iterator
if ($this->names || $this->notNames) {
$iterator = new Iterator\FilenameFilterIterator($iterator, $this->names, $this->notNames);
}
...
//使用SPL文件路径过滤iterator
if ($this->paths || $notPaths) {
$iterator = new Iterator\PathFilterIterator($iterator, $this->paths, $notPaths);
}
...
return $iterator;
}
追踪Iterator的current()
//class namespace Symfony\Component\Finder\Iterator\RecursiveDirectoryIterator
public function current()
{
//获取$subPathname,默认为""
if (null === $subPathname = $this->subPath) {
$subPathname = $this->subPath = (string) $this->getSubPath();
}
//获取文件名称
$subPathname .= $this->getFilename();
//获取路径名称
if ('/' !== $basePath = $this->rootPath) {
$basePath .= $this->directorySeparator;
}
//返回SplFileInfo实例
return new SplFileInfo($basePath.$subPathname, $this->subPath, $subPathname);
}
回到getConfigurationFiles(),执行每一个文件并将文件路径即名称存储在$files数组中
protected function getConfigurationFiles(Application $app)
{
$files = [];
$configPath = realpath($app->configPath());
//Finder继承了IteratorAggregate
foreach (Finder::create()->files()->name('*.php')->in($configPath) as $file) {
$directory = $this->getNestedDirectory($file, $configPath);
$files[$directory.basename($file->getRealPath(), '.php')] = $file->getRealPath();
}
ksort($files, SORT_NATURAL);
return $files;
}
$files:
array:11 [▼
“app” => “/usr/local/var/www/auth/config/app.php”
“auth” => “/usr/local/var/www/auth/config/auth.php”
“broadcasting” => “/usr/local/var/www/auth/config/broadcasting.php”
“cache” => “/usr/local/var/www/auth/config/cache.php”
“database” => “/usr/local/var/www/auth/config/database.php”
“filesystems” => “/usr/local/var/www/auth/config/filesystems.php”
“mail” => “/usr/local/var/www/auth/config/mail.php”
“queue” => “/usr/local/var/www/auth/config/queue.php”
“services” => “/usr/local/var/www/auth/config/services.php”
“session” => “/usr/local/var/www/auth/config/session.php”
“view” => “/usr/local/var/www/auth/config/view.php”
]
回到loadConfigurationFiles():
//class Iluminate\Foundation\Bootstrap\LoadConfiguration
protected function loadConfigurationFiles(Application $app, RepositoryContract $repository)
{
//获取config目录下的文件名称组成的数组
$files = $this->getConfigurationFiles($app);
//将config目录下的文件名即文件内容存储在$config内
foreach ($files as $key => $path) {
$repository->set($key, require $path);
}
}
遍历 f i l e s 将 信 息 存 储 在 files将信息存储在 files将信息存储在repository中:
//class Illuminate\Config\Repository
public function set($key, $value = null)
{
$keys = is_array($key) ? $key : [$key => $value];
foreach ($keys as $key => $value) {
Arr::set($this->items, $key, $value);
}
}
//class Illuminate\Support\Arr
public static function set(&$array, $key, $value)
{
...
$array[array_shift($keys)] = $value;
return $array;
}
$reposiroty:
Repository {#24 ▼
#items: array:11 [▼
“app” => array:13 [▶]
“auth” => array:4 [▶]
“broadcasting” => array:2 [▶]
“cache” => array:3 [▶]
“database” => array:4 [▶]
“filesystems” => array:3 [▶]
“mail” => array:9 [▶]
“queue” => array:3 [▶]
“services” => array:4 [▶]
“session” => array:15 [▶]
“view” => array:2 [▶]
]
}
回到bootstrap(),开始检测开发环境,设定时区及编码集,很简单的回调函数这里就不尽兴解释了
//class Iluminate\Foundation\Bootstrap\LoadConfiguration
public function bootstrap(Application $app)
{
$items = [];
//校验是否存在缓存配置文件
if (file_exists($cached = $app->getCachedConfigPath())) {
$items = require $cached;
$loadedFromCache = true;
}
//创建$config实例并存储在容器中
$app->instance('config', $config = new Repository($items));
//不存在缓存配置文件到时候加载配置文件
if (! isset($loadedFromCache)) {
$this->loadConfigurationFiles($app, $config);
}
//检测开发环境
$app->detectEnvironment(function () use ($config) {
return $config->get('app.env', 'production');
});
//设置时区
date_default_timezone_set($config->get('app.timezone', 'UTC'));
//设置编码字符集
mb_internal_encoding('UTF-8');
}
OK,到这里结束吧。。。