学习要点
- 常用函数
- 命名空间
- 类的自动加载
常用函数
class_exists
作用:检查类是否已定义
语法格式:
bool class_exists ( string $class_name [, bool $autoload = true ] )
参数说明:
class_name:类名。名字的匹配是不分区大小写的。
autoload:是否默认调用 __autoload。
interface_exists
作用:检查接口是否已被定义
语法格式:
bool interface_exists ( string $interface_name [, bool $autoload = true ] )
参数说明:
interface_name:接口名。
autoload:默认是否调用 __autoload。
method_exists
作用:检查类的方法是否存在
语法格式:
bool method_exists ( mixed $object , string $method_name )
参数说明:
object:对象示例或者类名。
method_name:方法名。
is_object
作用: 检测变量是否是一个对象。
语法格式:
bool is_object ( mixed $var )
如果 var 是一个 object 则返回 TRUE,否则返回 FALSE。
类似数据类型检测用法: is_bool()、is_int()、is_integer()、is_float()、is_string() 和 is_array()。
命名空间
官方文档对PHP命名空间的说明:
http://php.net/manual/zh/language.namespaces.php
简要
命名空间解决的问题:
- 用户编写的代码与PHP内部的类/函数/常量或第三方类/函数/常量之间的名字冲突。
- 为很长的标识符名称(通常是为了缓解第一类问题而定义的)创建一个别名(或简短)的名称,提高源代码的可读性。
PHP 命名空间提供了一种将相关的类、函数和常量组合到一起的途径。
定义
语法格式
<?php namespace MyProject;
语法说明:除了用于定义源文件编码方式的 declare 语句,所有非 PHP 代码包括空白符都不能出现在命名空间的声明之前。
定义单个命名空间
<?php namespace MyProject;
相同namesapce声明可以出现在多个文件中,用于将代码组织在一起。
定义子命名空间
与目录和文件的关系很象,PHP 命名空间也允许指定层次化的命名空间的名称。因此,命名空间的名字可以使用分层次的方式定义。
例如:声明分层次的单个命名空间
<?php namespace MyProjectApplicationAdmin; const CONNECT_OK = 1; class Connection { /* ... */ } function connect() { /* ... */ } ?>
命名空间基础用法
访问命名空间
使用命名空间之前,必须了解 PHP 是如何知道要使用哪一个命名空间中的元素的。
文件的的访问:
- 相对文件名形式如foo.txt。它会被解析为 currentdirectory/foo.txt,其中 currentdirectory 表示当前目录。因此如果当前目录是 /home/foo,则该文件名被解析为/home/foo/foo.txt。
- 相对路径名形式如subdirectory/foo.txt。它会被解析为 currentdirectory/subdirectory/foo.txt。
- 绝对路径名形式如/main/foo.txt。它会被解析为/main/foo.txt。
同理,PHP命名空间中使用三种方式引入类。
- 非限定名称,或不包含前缀的类名称。例如 $a=new foo(); 或 foo::staticmethod();。如果当前命名空间是 currentnamespace,foo 将被解析为currentnamespacefoo。如果使用 foo 的代码是全局的,不包含在任何命名空间中的代码,则 foo 会被解析为foo。 注意:如果命名空间中的函数或常量未定义,则该非限定的函数名称或常量名称会被解析为全局函数名称或常量名称。
- 限定名称,或包含前缀的名称。例如 $a = new subnamespacefoo(); 或 subnamespacefoo::staticmethod();。如果当前的命名空间是currentnamespace,则 foo 会被解析为 currentnamespacesubnamespacefoo。如果使用 foo 的代码是全局的,不包含在任何命名空间中的代码,foo 会被解析为subnamespacefoo。
- 完全限定名称,或包含了全局前缀操作符的名称。例如, $a = new currentnamespacefoo(); 或 currentnamespacefoo::staticmethod();。在这种情况下,foo 总是被解析为代码中的字面名(literal name)currentnamespacefoo。
命名空间是对PHP元素逻辑上进行分类,来实现对类、函数和常量管理(无法管理变量)。
示例
<?php namespace MyProject { //定义常量 CONST E = 2.78; //定义函数 function getNameSpace() { echo __NAMESPACE__ . " ";//输出命名空间命名 } //定义类 class MyClass { public function m() { echo __NAMESPACE__ . "," . __METHOD__ . " ";//输出方法名称和命名空间名称 } } } namespace MyProject2 { //定义常量 CONST E = 2.78; //定义函数 function getNameSpace() { echo __NAMESPACE__ . " ";//输出命名空间命名 } //定义类 class MyClass { public function m() { echo __NAMESPACE__ . "," . __METHOD__." ";//输出方法名称和命名空间名称 } } } namespace MyProject3 { CONST C = 888; function getNameSpace() { echo __NAMESPACE__ . " ";//输出命名空间命名 } class MyClass { public function m() { echo __NAMESPACE__ . "," . __METHOD__." ";//输出方法名称和命名空间名称 } } echo "访问全局变量不需要添加前缀:" . __NAMESPACE__ . " "; echo "访问当前命名空间的常量不需要添加前缀:" . C . " "; echo "访问当前空间函数:".getNameSpace()." "; $mc=new MyClass();//非限定名访问当前空间类 $mc->m(); use MyProject2; $mc2= new MyProject2MyClass();//限定名访问MyProject2命名空间下的类 $mc2->m(); $mc3=new MyProjectMyClass();//全限定名访问MyProject空间下的类 $mc3->m(); }
说明:
- 在同一个文件表示多个空间,空间的表示要保持一致:或者一起使用"{}"或者一起不使用。
- 访问当前空间的元素不需要添加前缀。
- 没有使用use引入其他命名空间,如果要使用该空间的元素,需要使用全限定名称访问。
- 使用use分为两种情况,一种是use空间:访问类需要使用非权限定名称;另一种是use到具体类,使用非限定名访问。
父空间和子空间之间的访问
通过全限定名和限定名的方式访问。
示例:
<?php //子空间 namespace AdminHomeAction; function m(){ echo __NAMESPACE__." "; } //父空间 namespace AdminHome; function m(){ echo __NAMESPACE__." "; } m();//非限定名方式访问本空间函数(父空间函数) AdminHomeActionm();//全限定名称访问子空间函数 Actionm();//限定名方式访问子空间函数
非限定名称访问:访问当前空间元素。
限定名称访问:访问子空间元素。
全限定名称访问:访问任意一个空间元素。(子空间访问父空间元素)
动态变量访问命名空间
使用动态变量参数表示类、函数或者变量,必须使用完全限定名称(包括命名空间前缀的类名称)。
注意因为在动态的类名称、函数名称或常量名称中,限定名称和完全限定名称没有区别,因此其前导的反斜杠不是必要的。
示例:
<?php //使用动态变量参数表示类、函数或者变量,必须使用完全限定名称(包括命名空间前缀的类名称)。 //注意因为在动态的类名称、函数名称或常量名称中,限定名称和完全限定名称没有区别,因此其前导的反斜杠不是必要的。 namespace example1 { const constname = "global"; function m() { echo __FUNCTION__, "=== "; } class MyClass { function __construct() { echo __METHOD__, " "; } } } namespace example2 { //访问本空间下的元素代码略 $a = 'example1MyClass';//注意:如果使用双引号,则需要使用双反斜杠 $b = "example1\MyClass"; $obja = new $a();//动态类名 $objb = new $b(); $c="\example1\constname"; echo constant($c)," "; $d='example1m'; $d(); }
命名空间的导入和别名
允许通过别名引用或导入外部的完全限定名称,是命名空间的一个重要特征。
所有支持命名空间的PHP版本支持三种别名或导入方式:为类名称使用别名、为接口使用别名或为命名空间名称使用别名。PHP 5.6开始允许导入函数或常量或者为它们设置别名。
别名:use引入类导致两个空间类名冲突的时候,可以在引入类的时候为引入类起别名。
使用use关键字实现。
示例:
<?php namespace HomeView { class MyClass { public function __construct() { echo __CLASS__; } } } namespace AdminController { use HomeViewMyClass as MC; $obj = new MC(); }
注意:use语句后面的空间路径不可以使用前导反斜杠,因为use必须使用全限定名称导入命名空间,而不会根据当前文件的相对位置进行解析。
使用use导入多个命名空间,语法格式:
use 命名空间1,命名空间2,...命名空间n;
导入操作只影响非限定名称和限定名称。完全限定名称由于是确定的,故不受导入的影响。
问题:在A空间引入B空间文件,A和B空间有同样的函数,是如何运行的?
定义D05A.php
<?php namespace A; function m(){ echo "A命名空间".__NAMESPACE__." "; }
定义D05B.php
namespace B; function m(){ echo "B命名空间".__NAMESPACE__." "; } include "D05A.php";
m();//输出的结果是?输出B空间m函数
Am();//输出A空间m函数。
运行结果:
原因分析:无论是使用require还是include指令,在编译阶段没有把D05A.php文件载入到D05B.php文件。
如何访问加载空间中的元素?
使用完全限定访问。
全局空间的访问
如果没有定义命名空间,则表示全局空间元素。使用“”访问。
示例代码:
D05A.php文件
<?php function m(){ echo "A命名空间".__NAMESPACE__." "; }
D05B.php文件
<?php namespace B; function m(){ echo "B命名空间".__NAMESPACE__." "; } require "D05A.php"; //m();//访问B空间m函数 m();//访问全局命名空间
类的自动加载
示例目录结构如下图,在控制器和模型模块中,分别按照规范定义了相关类和命名空间。
类名规范:类名骆驼命名法则.class.php
空间命名规范:目录名目录名..
问题:假如需要在index.php中实例化模块中的类,在实例化的时候需要加载类文件。
如果项目规模增加,需要加载的类文件越来越多,如何解决?__autoload()函数能够解决吗?
function __autoload($className){ include $className.'.class.php'; }
如上__autoload()函数只能加载当前命名空间下的类文件,无法加载其他空间文件。
解决方案:自定义自动加载函数,并注册到PHP全局加载中。
定义Common类,注册自定义自动加载函数。
代码和说明如下:
<?php namespace Core; class Common { //定义静态自动加载函数 public static function myAutoLoad($className){ //完成由命名空间构成的类路径信息的类文件的加载 //例如:ApplicationAdminControllerAdminController //问题:include等加载函数使用的是正斜杠路径,需要进行转换为:Application/Admin/Controller/AdminController.".class.php" $path=str_replace("\","/",$className); $filePath=$path.".class.php"; if(file_exists($filePath)) { include_once $filePath; }else{ die("无法加载文件:".$filePath); } } //注册自动加载函数 public static function registerAutoLoad(){ spl_autoload_register("self::myAutoLoad"); } }
index.php文件中执行自动加载注册,并测试运行:
<?php //require "Application/Admin/Controller/AdminController.class.php"; require "Core/Common.class.php"; coreCommon::registerAutoLoad(); //引入命名空间类实例化 use ApplicationAdminControllerAdminController; new AdminController(); //实例化限定名类 new ApplicationHomeModelHomeModel();