类自动加载介绍我们在PHP代码中加载类时,必须包含或需要某个类文件。但是遇到了类似的情况,例如:require"Class1.php";require"Class2.php";$boy=$_GET['sex']=0?true:false;if($boy){$class1=newClass1();}else{$class2=newClass2();}如果我们需要判断一个人的性别,如果是男的就实例化类class1,如果是女的就实例化类class2。那么问题来了:这段代码,我每次只需要执行一个实例化对象,却要加载这两个类文件。PHP针对这个问题提出了解决方案spl_auto_register()。spl_auto_register($autoload_function=null,$throw=true,$prepend=false)的概念是在php5.1中提出的。该函数包含3个参数①autoload_function这是一个函数[方法]名称,可以是字符串也可以是数组(用于调用类方法)。这个函数(方法)的作用是包含(requeire)需要new的class文件,这样new的时候就找不到文件了。其实就是封装了整个项目的include和require功能。②$throw该参数指定当autoload_function无法注册时spl_autoload_register()是否应该抛出异常。③如果为true,那么spl_autoload_register()会在文件前面自动加载,有时也会在后面。用法然后在有了这个函数之后,写functionload($class){require"./{$class}.php";}spl_autoload_register('load');if($boy){$class1=newClass1();}else{$class2=newClass2();}程序执行过程如下://正常流程new一个对象-->找不到对象-->报错//引入spl_autoload_register后,新建一个对象-->找不到对象-->spl_autoload_register告诉我试试-->加载成功后,我们执行加载函数,通过类拼接,完成加载函数__autoload()的自动加载该类在前面我们在讲spl_autoload_register的时候已经讲过了。今天我们说说另一种__autoload(),在php7中是不推荐的。php的__autoload函数是一个神奇的函数。在这个功能出现之前,如果一个php文件引用了100个对象,那么这个文件需要使用include或者require引入100个class文件,会导致php文件非常庞大。于是就有了这个__autoload函数。什么时候调用__autoload函数?在php文件中使用new关键字实例化一个对象时,如果php文件中没有定义该类,就会触发__autoload函数。这时候定义类的php文件就可以导入了,然后,就可以实例化成功了。(注意:如果需要实例化对象,如果已经在这个文件中找到类的定义,则不会触发__autoload函数)他和spl_autoload_register的区别在于当__autoload和spl_autoload_register出现在文件中的时候同时,以spl_autoload_register开头的是prevailingnamespace。之前我们讲过类的自动加载,然后我就在想这个问题。我们在使用框架写代码的时候,不是每次在另一个文件调用其他类的时候都写spl_autoload_register方法吗?那我们是如何实现的呢?原理原来是我们的php在5.3引入了命名空间的概念(这也是大部分框架不支持5.3之前版本的原因之一)。简而言之,命名空间是一种标识,其主要目的是解决命名冲突问题。就像在日常生活中,有很多同名的人,如何区分这些人呢?然后需要添加一些额外的标志。以工作单位为标志似乎也不错,这样就不用担心“撞名”的尴尬了。命名空间分类fullyqualifiednamespacequalifiednamespacenewChengdu\XuDashuai();//限定类名new\Chengdu\XuDashuai();//完全限定类名在当前命名空间没有声明的情况下,限定类名和完全限定类名是等价的。因为如果不指定空格,默认是global()。namespaceUnitedStates;newChengdu\徐大帅();//美国\成都\徐大帅(实际结果)new\成都\徐大帅();//Chengdu\DashuaiXu(实际结果)这个例子展示了命名空间下有限类的使用类名和全限定类名的区别。(全限定类名=当前命名空间+限定类名)/*importnamespace*/useChengdu\DashuaiXu;newDashuaiXu();//Chengdu\DashuaiXu(实际结果)/*设置别名*/useChengdu\DashuaiXuASCEO;newCEO();//Chengdu\DashuaiXu(actualresult)/*anycase*/new\Chengdu\DashuaiXu();//Chengdu\DashuaiXu(actualresult)usesnamespaceonly让类名有前缀,不易发生冲突了,系统还是不会自动导入。如果没有导入文件,系统会在抛出“ClassNotFound”错误之前触发__autoload()或spl_autoload_register函数,并将限定的类名作为参数传递。以上例子是建立在你手动导入相关文件的前提下,否则系统会抛出“Class'ChengduXuDashuai'notfound”。因为她不知道这个文件在哪里。所以在引入命名空间之后,引入了自动加载接下来,我们在使用命名空间加载我们的类使用命名空间自动加载类的小实验首先,我们在一个新文件中定义//School.phpnamespacetop;classSchool{function__construct(){echo'这是'.__CLASS__.'的实现。班级';}}这个当然不重要,重要的是我们调用了他的函数。我们在同一个目录下创建一个index.php文件(不同的文件也可以,只要写好映射关系即可)//index.phpspl_autoload_register(function($class){//看我们的类名,有没有对应的Path$map=['top\\School'=>'./School.php'];$file=$map[$class];//检查对应文件是否存在if(file_exists($file))include$file;});echo"Start
";newtop\School();结果开始。这是top\School类的实现。我们利用类名和类地址的映射关系来实现我们的自动加载。然而,这也意味着每次我们添加一个文件时,我们都必须更新我们的映射文件。这样的数组在大型系统中维护的映射关系无疑是非常麻烦的。那么有没有更好的办法呢?不了解PSR4自动加载规范的童鞋,可以看这里PSR4中文文档的具体解释。以下内容摘自上述链接。我觉得上面两篇文章已经解释的很透彻了>PSR-4规范中肯定有一个顶级命名空间,它的含义就是代表一个特殊的目录(文件基目录)。子命名空间表示类文件相对于文件基目录的路径(相对路径),类名与文件名一致(注意大小写的区别)。例如:全限定类名appviewnewsIndex中,如果app代表C:Baidu,那么这个类的路径就是C:BaiduviewnewsIndex.php下面我们以解析appviewnewsIndex为例,写一个简单的Demo:$class='app\view\news\Index';/*顶级命名空间路径映射*/$vendor_map=array('app'=>'C:\Baidu',);/*解析类名文件路径*/$vendor=substr($类,0,strpos($class,'\\'));//取出顶层命名空间[app]$vendor_dir=$vendor_map[$vendor];//文件基目录[C:\Baidu]$rel_path=dirname(substr($class,strlen($vendor)));//相对路径[/view/news]$file_name=basename($class).'.php';//filename[Index.php]/*输出文件所在的路径*/echo$vendor_dir.$rel_path。DIRECTORY_SEPARATOR。$文件名;通过这个Demo可以看到将限定类名转换为路径的过程。所以现在让我们以规范的面向对象的方式实现自动加载器。首先我们创建一个文件Index.php,它在appmvcviewhome目录下:}}然后我们创建一个加载类(不需要命名空间),它在目录中:classLoader{/*pathmap*/publicstatic$vendorMap=array('app'=>__DIR__.DIRECTORY_SEPARATOR.'app',);/***自动加载器*/publicstaticfunctionautoload($class){$file=self::findFile($class);如果(file_exists($file)){self::includeFile($file);}}/***解析文件路径*/privatestaticfunctionfindFile($class){$vendor=substr($class,0,strpos($class,'\\'));//顶级命名空间$vendorDir=self::$vendorMap[$vendor];//文件基目录$filePath=substr($class,strlen($vendor)).'.php';//文件相对路径returnstrtr($vendorDir.$filePath,'\\',DIRECTORY_SEPARATOR);//文件标准路径}/***importfile*/privatestaticfunctionincludeFile($file){如果(is_file($file)){包括$file;最后将Loader类中的autoload注册到spl_autoload_register函数中:include'Loader.php';//引入加载器spl_autoload_register('Loader::autoload');//注册自动加载new\app\mvc\view\home\Index();//实例化未引用的类/***output:
