一步步编写简单的PHP的Framework(四)

 班级聚会刚回来,继续写这个文章吧!!php

      上一篇文章我提了一个问题,怎么实现自动载入一个类呢?框架

       实际上PHP已经有相应的机制能够实现这个功能了,这个机制就是autoload,它会在试图使用还没有被定义的类时自动调用。函数

       如今咱们能够在Route.php中的开头定义autoload函数(固然,这样是不规范的,可是为了简单,先这么作)。测试

        咱们如今的自动导入须要导入两类文件,一类是框架类文件,另一类是用户应用模块的类文件,为了简化代码,能够假设框架的全部文件都存放在/Library/Test目录下面,用户类文件都存放在/UserApps/Modules目录下面,而且只会在Controllers,Models,Helpers这三个目录下面,而且这几个目录下面没有子目录。ui

         对于这个自动导入的函数,它须要首先尝试导入框架类文件,若是该文件不存在,说明是用户类文件,而后再尝试导入用户类文件,若是是,那么include它。.net

         注意:设计

             因为要频繁使用UserApps/Modules这个目录,因此我定义了一个MODULES_PATH这个常量;code

       

function __autoload($className) {
	$frameworkFileName = FRAMEWORK_PATH . '/' . $className . '.php';
	if(is_file($frameworkFileName)) {
		include $frameworkFileName;
	} else {
		//用户类文件
		$controllerFileName = MODULES_PATH . '/Controllers/' . $className . '.php';
		if(is_file($controllerFileName)) {
			include $controllerFileName;
		} else {
			$modelFileName = MODULES_PATH . '/Models/' . $className . '.php';
			if(is_file($modelFileName)) {
				include $modelFileName;
			} else {
				$helperFileName = MODULES_PATH . '/Helpers/' . $className . '.php';
				if(is_file($helperFileName)) {
					include $helperFileName;
				} else {
					throw new Exception("class not found");
				}
			}
		}
	}
}

 

 

           当你把这个函数写完以后,能够在以前已经写好的IndexController.php中去测试一下,好比在和IndexController同一目录下面创建一个文件Test.php,文件代码以下:blog

 

<?php
class Test {
      public function test() {
         echo 'Test';
      }
}

而后在IndexController.php中使用以下:ip

 

 

<?php
class IndexController {
	public function index() {
		$test = new Test();
                $test->test();
	}
}

若是出现Test,那么恭喜你,自动导入成功了!!

 

             如今再考虑一下,若是针对一个很复杂的项目,使用这种方式来自动导入,有什么问题吗?

             其实问题是比较严重的,首先对于框架的文件,咱们不可能将全部文件都存放在一个目录下面,这样当文件多了以后就检索就麻烦了;对于用户类文件,好比控制器的文件,咱们不可能将它所有存放在一个目录下面,咱们须要按照模块切分目录等。若是用__autoload来实现的话,这个函数的代码量就太大了,并且若是有一个地方的修改那么就可能牵一发而动全身,这样对于项目的维护是很不利的。

             那么咱们怎么解决这个问题呢?

             方法一:

                 咱们定义不少辅助函数,好比导入框架文件,咱们定义一个frameworkAutoloadHelper,对于用户文件定义一个userAutoloadHelper,而后将业务逻辑存放在这两个函数中,最后在__autoload中调用这两个函数便可,当用户功能须要修改的时候,代码维护性就好一些了;

             方法2:

                 在SPL中已经定义了一个spl_autoload_register,可使用这个来说自动导入的功能分摊到多个类中,并且还能够将自动导入的控制权交给用户,这对于框架来讲是比较重要的,因此,我推荐使用这种方式。

                  具体这种方式怎么实现,读者能够本身查查PHP手册,也能够查看我写的Toper框架的相应实现,具体实现类在/Library/Toper/Loader.class.php。

           当咱们使用了spl_autoload_register以后,是否是一切就高枕无忧了?

            其实不是,咱们如今能够想一下是否能够去除自动导入呢,由于当业务逻辑很复杂而且自动导入设计的又不是特别好的时候,自动导入的效率就不是很高了!!

             不用自动导入,难道仍是使用include?No。

             你们都知道include,include_once,require,require_once的区别吧!!

             include和require每次调用都会包含这个文件,include_once和require_once只会导入一次,include若是包含了一个不存在的文件,只会抛出警告,程序会继续执行,而require会中止执行,因此这四个函数我比较建议使用require_once,可是很遗憾,这个函数效率很低,由于它要考虑的东西太多了!!

               PS:使用这四个函数的时候,最好使用绝对路径,这样效率要高一些;

              若是咱们使用require,那么效率会高不少,可是若是使用require怎么实现require_once的功能呢?

              我给你们提供一个思路,使用static变量:

 

<?php
function testRequireOnce($file) {
      static $_config = array();
      if(!isset($_config[$file])) {
         require $file;
         $_config[$file] = $file;
      }
}

 

            固然,还可使用class_exists来断定。

             此次的代码能够点此下载

相关文章
相关标签/搜索