php的类的自动加载和控制器消息转发
2018-09-30 本文已影响0人
鸿雁长飞光不度
1.类的自动加载
在php中引入文件可以使用require或者include关键字,但是如果类非常多的话,手动引入十分麻烦,所以提供了一种便利的方式,通过
spl_autoload_register
函数,这个函数可以注册一个函数,用来在系统调用一个不存在的类的时候进行处理,可以在这个函数中进行处理,因为涉及到自动加载,必然有类的命名要有规则,因为命名空间是有层次的,目录结构也是有层次的,我们完全将命名空间解析成目录,然后加载文件,对于命名空间和目录不匹配的情况也可以通过自己定义映射关系找到。下面结合php的反射,模拟实现了thinkphp消息向控制的转发,动态参数注入,initialize方法。
/**
* 文件名和类名相同,大驼峰原则
* 命名空间名和文件夹名相同(全部小写)
* m=index?a=index
*/
class PsrAutoLoad{
protected static $classPaths = [
];
protected static $map = [
];
function __construct()
{
spl_autoload_register([$this,'autoload']);
}
//调用一个不存在的类的时候会到这里来,得到类的名字
protected function autoload($className)
{
if (isset(self::$classPaths[$className])){
$classPath = self::$classPaths[$className];
}else{
$classPath = $this->getClassPath($className);
if (file_exists($classPath)){
self::$classPaths[$className] = $classPath;
}else{
echo $className." Not Found"."\n";
}
}
require $classPath;
}
//获取类的文件信息
protected function getClassPath($className)
{
$nameSpace = substr($className,0,strrpos($className,'\\')); //命名空间名
$className = substr($className,strrpos($className,'\\')+1);//类名
if (isset(self::$map[$nameSpace])){
$classPath = __DIR__.DIRECTORY_SEPARATOR.self::$map[$nameSpace].DIRECTORY_SEPARATOR.$className.".php";
}else{
$classPath = __DIR__.DIRECTORY_SEPARATOR.str_replace('\\','/',$nameSpace).DIRECTORY_SEPARATOR.$className.".php";
}
return $classPath;
}
//手动添加映射
public static function addMap($space,$path = null,$isOverride = false)
{
if (is_string($space)){
if (is_null($path)){
unset(self::$map[$space]);
}else{
if (!isset(self::$map[$space]) || $isOverride){
self::$map[$space] = $path;
}
}
}elseif (is_array($space)){
if (empty(self::$map) || $isOverride){
self::$map = $space;
}else{
self::$map = array_merge(self::$map,$space);
}
}
}
}
function index()
{
$m = isset($_GET['m'])?$_GET['m']:'index'; //类名
$a = isset($_GET['a'])?$_GET['a']:'index'; //方法
new PsrAutoLoad();
PsrAutoLoad::addMap([
'controller' => 'app/controller'
]);
$m = '\\controller\\'.ucfirst($m); //模拟通过index入口进来访问的命名空间下的类
$reflect = new ReflectionClass($m);
if ($reflect->hasMethod($a)){
$instance = new $m();
$method = $reflect->getMethod($a);
$params = $method->getParameters();
if (!empty($params)){
$dynamicParams = [];
foreach ($params as $param){ //param 为 ReflectionParameter
$class = $param->getClass();
$val = null;
if ($class){ //如果参数是类
$className = $class->getName();
$val = new $className();
}else{
$paramName = $param->getName();
$val = isset($_GET[$paramName])?$_GET[$paramName]:null;
}
$defaultValue = $param->isDefaultValueAvailable()?$param->getDefaultValue():null;
$dynamicParams[] = $val?$val:$defaultValue;
}
if ($reflect->hasMethod('__initialize')){
call_user_func([$instance,'__initialize']); //有前置方法前置调用
}
$method->invokeArgs($instance,$dynamicParams);
}else{
$method->invoke($instance);
}
}else{
echo 'Class '.$m.' method '.$a.' not found !!';
}
}
index();
<?php
namespace controller;
use app\lib\Request;
/**
* Created by PhpStorm.
* User: guodong
* Date: 2018/9/28
* Time: 下午3:03
*/
class Index
{
//调用每个方法前自动调用的方法
public function __initialize()
{
echo '通用调用';
}
public function index(Request $request, $name)
{
var_dump($request->getParams());
echo $name;
echo '这是'.__CLASS__.'类的'.__METHOD__.'方法'."\n";
}
public function index2()
{
echo '这是'.__CLASS__.'类的'.__METHOD__.'方法'."\n";
}
}
<?php
namespace app\lib;
class Request{
protected $params = [];
public function __construct()
{
$this->params = $_GET;
}
public function getParams()
{
return $this->params;
}
}