一步步编写PHP的Framework(五)
不知道大家注意了没有,前几篇文章我都没有涉及到配置文件,可是在一个项目中,配置文件又是比不可少的。
现在假设将Route.php中的默认控制器和Action变为可配置的,怎么弄呢?
我们使用最简单的方式:
1 |
2 | $defaultController = 'Index'; |
3 | $defaultAction = 'index'; |
然后在Route.php中include这个文件:
1 |
2 | include APP_PATH . '/config.php'; |
1 | $controller = empty($_GET['c']) ? $defaultController : trim($_GET['c']); //设置了默认的控制器 |
2 | $action = empty($_GET['a']) ? $defaultAction : trim($_GET['a']); //设置了默认的Action |
当然也可以使用这种方式:
1 |
2 | return array( |
3 | 'defaultController' => 'Index', |
4 | 'defaultAction' => 'index' |
5 | ); |
还是在Route.php中include:
1 |
2 | $config = include APP_PATH . '/config.php'; |
1 | $controller= empty($_GET['c']) ? $config['defaultController'] : trim($_GET['c']); //设置了默认的控制器 |
2 | $action = empty($_GET['a']) ? $config['defaultAction'] : trim($_GET['a']); //设置了默认的Action |
但是由于配置文件很有可能在整个框架运行过程的各个类都有用到,而前两种方式都只能在某一个类里面的某一个方法中使用,怎么让它在各个类都可以使用呢?
我们可以可以使用一个static方法来解决,比如专门定义一个Config类来存放配置信息,Config::get来读取配置信息,Config::set来设置配置信息,具体做法读者可以自己去尝试一下。
当然我不准备采用这种方式,可能当时我看Thinkphp源码的时候被它优雅的特殊函数C迷住了吧,后面我在写Toper的时候也使用了一些特殊的函数,而C主要是负责设置和读取配置信息,个人观点,面向对象是必要的,但是不是什么都要面向对象,所以我准备定义一个function.php来存放一些公有的函数,我把它称为公有函数库。
由于有了公有函数库,我们可以将上一篇里面的自动导入(__autoload)也转移到这个文件中,因为在Route.php出现一段__autoload的代码还是挺诡异的!!
好了,怎么实现刚才我们说的通过一个函数来实现配置信息的设置和读取呢?
好了,先展示我在Toper中的实现吧:
01 | function C($name = null,$val = null) { |
02 | static $_config = array(); |
03 | if(empty($name)) { |
04 | return $_config; |
05 | } elseif(is_string($name)) { |
06 | if(empty($val)) { |
07 | if(!strpos($name,'=>')) { |
08 | //一维 |
09 | return isset($_config[$name]) ? $_config[$name] : null; |
10 | } else { |
11 | //目前只支持二维 |
12 | $name = explode('=>',$name); |
13 | returnisset($_config[$name[0]][$name[1]]) ? $_config[$name[0]][$name[1]] : null; |
14 | } |
15 | } else { |
16 | if(!strpos($name,'=>')) { |
17 | //直接设置 |
18 | $_config[$name] = $val; |
19 | } else { |
20 | //设置二维 |
21 | $name = explode('=>',$name); |
22 | $_config[$name[0]][$name[1]] = $val; |
23 | } |
24 | } |
25 | } elseif(is_array($name)) { |
26 | foreach($name as $key=>$value) { |
27 | $_config[$key] = $value; |
28 | } |
29 | return ; |
30 | } else { |
31 | throw new Exception('参数类型出错'); |
32 | return ; |
33 | } |
34 | } |
看着代码挺长的,实际上原理很简单,如果传递的参数只有一个,那么第二个参数就调用默认参数,即NULL,再识别是否第一个参数是否是字符串,那么这个函数就识别为读取,如果第二个参数不为空或第一个参数为数组,那么就识别为设置!!
由于我自己现在比较懒,而且我用这个函数用的函数蛮顺手的,所以在这儿我就直接用这个函数来作为例子了,更多内容可以查看Toper的/Library/Toper/function.php。
比如现在要读取defaultController,那么只要使用C('defaultController')即可,如果要设置,那么使用C('defaultController','Index')!!!
现在我们只需要在入口文件中导入这个function.php即可:
1 |
2 | defined('APP_PATH') define('APP_PATH',dirname(__FILE__) . '/..'); |
3 | defined('FRAMEWORK_PATH') define('FRAMEWORK_PATH',APP_PATH . '/Library/Test'); |
4 | defined('MODULES_PATH') define('MODULES_PATH',APP_PATH . '/UserApps/Modules'); |
5 | include FRAMEWORK_PATH . '/function.php'; |
6 | include FRAMEWORK_PATH . '/Route.php'; |
7 | Route::run(); |
大家可能注意到了,C函数最开始的时候,里面没有存放任何元素,那么我们怎么样进行初始化,将配置文件的内容写入C函数呢?
之前我们将配置文件存放在项目根目录,这样实际上是不符合之前我们的约定的规范,所以现在讲这个配置文件剪切到/UserApps/Configs目录下面,为了更方便的使用这个路径,我们定义一个CONFIGS_PATH来指向配置文件的路径。
现在我们看看入口文件变成了什么样了:
1 |
2 | defined('APP_PATH') define('APP_PATH',dirname(__FILE__) . '/..'); |
3 | defined('FRAMEWORK_PATH') define('FRAMEWORK_PATH',APP_PATH . '/Library/Test'); |
4 | defined('MODULES_PATH') define('MODULES_PATH',APP_PATH . '/UserApps/Modules'); |
5 | defined('CONFIGS_PATH') define('CONFIGS_PATH',APP_PATH . '/UserApps/Configs'); |
6 | include FRAMEWORK_PATH . '/function.php'; |
7 | C(include CONFIGS_PATH . '/config.php'); //写入配置信息 |
8 | include FRAMEWORK_PATH . '/Route.php'; |
9 | Route::run(); |
然后我们修改一下Route.php
01 |
02 | class Route { |
03 | public static function run() { |
04 | $controller= empty($_GET['c']) ? C('defaultController') : trim($_GET['c']); //设置了默认的控制器 |
05 | $action= empty($_GET['a']) ? C('defaultAction') : trim($_GET['a']); //设置了默认的Action |
06 | $controllerBasePath = APP_PATH . '/UserApps/Modules/Controllers/'; |
07 | $controllerFilePath = $controllerBasePath . $controller . 'Controller.php'; |
08 | if(is_file($controllerFilePath)) { |
09 | include $controllerFilePath; |
10 | $controllerName = $controller . 'Controller'; |
11 | if(class_exists($controllerName)) { |
12 | $controllerHandler = new $controllerName(); |
13 | if(method_exists($controllerHandler,$action)) { |
14 | $controllerHandler->$action(); |
15 | } else { |
16 | echo 'the method does not exists'; |
17 | } |
18 | } else { |
19 | echo 'the class does not exists'; |
20 | } |
21 | } else { |
22 | echo 'controller not exists'; |
23 | } |
24 | } |
25 | } |