PHP命名空间(namespace)原理与用法详解


Posted in PHP onDecember 11, 2019

本文实例讲述了PHP命名空间(namespace)原理与用法。分享给大家供大家参考,具体如下:

PHP 命名空间(namespace)是在PHP 5.3中加入的,它可以解决以下两类问题:

  1. 用户编写的代码与PHP内部的类/函数/常量或第三方类/函数/常量之间的名字冲突。
  2. 为很长的标识符名称(通常是为了缓解第一类问题而定义的)创建一个别名(或简短)的名称,提高源代码的可读性。

我们在默认情况下,所有常量、类和函数名都放在全局空间下,就和PHP支持命名空间之前一样,命名空间通过关键字namespace 来声明,如果一个文件中包含命名空间,它必须在其它所有代码之前声明命名空间。我们来看下语法:

<?php 
// 定义代码在 'MyProject' 命名空间中 
namespace MyProject; 
// ... 代码 ...

我们也可以在同一个文件中定义不同的命名空间代码,如下:

<?php 
namespace MyProject;
const CONNECT_OK = 1;
class Connection { /* ... */ }
function connect() { /* ... */ }
namespace AnotherProject;
const CONNECT_OK = 1;
class Connection { /* ... */ }
function connect() { /* ... */ }
?>

不过我不建议使用这种语法在单个文件中定义多个命名空间,有需要的话,可以使用大括号形式的语法,如下:

<?php
namespace MyProject {
  const CONNECT_OK = 1;
  class Connection { /* ... */ }
  function connect() { /* ... */ }
}
namespace AnotherProject {
  const CONNECT_OK = 1;
  class Connection { /* ... */ }
  function connect() { /* ... */ }
}
?>

我们如果要将全局的非命名空间中的代码与命名空间中的代码组合在一起,只能使用大括号形式的语法,并且全局代码必须用一个不带名称的 namespace 语句加上大括号括起来,如下:

<?php
namespace MyProject {
const CONNECT_OK = 1;
class Connection { /* ... */ }
function connect() { /* ... */ }
}
namespace { // 全局代码
session_start();
$a = MyProject\connect();
echo MyProject\Connection::start();
}
?>

我们在声明命名空间之前唯一合法的代码是用于定义源文件编码方式的 declare 语句,要记住,除了这个之外的所有非 PHP 代码包括空白符都不能出现在命名空间的声明之前,如下:

<?php
declare(encoding='UTF-8'); //定义多个命名空间和不包含在命名空间中的代码
namespace MyProject {
const CONNECT_OK = 1;
class Connection { /* ... */ }
function connect() { /* ... */ }
}
namespace { // 全局代码
session_start();
$a = MyProject\connect();
echo MyProject\Connection::start();
}
?>

看个错误的写法:

<html>
<?php
namespace MyProject; // 命名空间前出现了“<html>” 会致命错误 - 命名空间必须是程序脚本的第一条语句
?>

与目录和文件的关系很像,PHP 命名空间也允许指定层次化的命名空间的名称,因此,命名空间的名字可以使用分层次的方式定义,模式如下:

<?php
namespace MyProject\Sub\Level; //声明分层次的单个命名空间
const CONNECT_OK = 1;
class Connection { /* ... */ }
function Connect() { /* ... */ }
?>

上述代码中,创建了常量 MyProject\Sub\Level\CONNECT_OK,类 MyProject\Sub\Level\Connection 和函数 MyProject\Sub\Level\Connect。

咱们再来看下PHP 命名空间中的类名的引用方式:

  1. 非限定名称,或不包含前缀的类名称,例如 $a=new foo(); 或 foo::staticmethod();。如果当前命名空间是 currentnamespace,foo 将被解析为 currentnamespace\foo。如果使用 foo 的代码是全局的,不包含在任何命名空间中的代码,则 foo 会被解析为foo。 警告:如果命名空间中的函数或常量未定义,则该非限定的函数名称或常量名称会被解析为全局函数名称或常量名称。
  2. 限定名称,或包含前缀的名称,例如 $a = new subnamespace\foo(); 或 subnamespace\foo::staticmethod();。如果当前的命名空间是 currentnamespace,则 foo 会被解析为 currentnamespace\subnamespace\foo。如果使用 foo 的代码是全局的,不包含在任何命名空间中的代码,foo 会被解析为subnamespace\foo。
  3. 完全限定名称,或包含了全局前缀操作符的名称,例如, $a = new \currentnamespace\foo(); 或 \currentnamespace\foo::staticmethod();。在这种情况下,foo 总是被解析为代码中的文字名(literal name)currentnamespace\foo。

咱们用来个文件来演示下,首先来看f1.php的代码:

<?php
namespace Foo\Bar\subnamespace; 
const FOO = 1;
function foo() {}
class foo
{
  static function staticmethod() {}
}
?>

之后就是f2.php的代码:

<?php
namespace Foo\Bar;
include 'f1.php';
const FOO = 2;
function foo() {}
class foo
{
  static function staticmethod() {}
}
/* 非限定名称 */
foo(); // 解析为函数 Foo\Bar\foo
foo::staticmethod(); // 解析为类 Foo\Bar\foo ,方法为 staticmethod
echo FOO; // 解析为常量 Foo\Bar\FOO
/* 限定名称 */
subnamespace\foo(); // 解析为函数 Foo\Bar\subnamespace\foo
subnamespace\foo::staticmethod(); // 解析为类 Foo\Bar\subnamespace\foo,
                 // 以及类的方法 staticmethod
echo subnamespace\FOO; // 解析为常量 Foo\Bar\subnamespace\FOO
/* 完全限定名称 */
\Foo\Bar\foo(); // 解析为函数 Foo\Bar\foo
\Foo\Bar\foo::staticmethod(); // 解析为类 Foo\Bar\foo, 以及类的方法 staticmethod
echo \Foo\Bar\FOO; // 解析为常量 Foo\Bar\FOO
?>

我们访问任意全局类、函数或常量,都可以使用完全限定名称,例如 \strlen() 或 \Exception 或 \INI_ALL。之后,咱们再来看下在命名空间内部访问全局类、函数和常量的实例:

<?php
namespace Foo;
function strlen() {}
const INI_ALL = 3;
class Exception {}
$a = \strlen('hi'); // 调用全局函数strlen
$b = \INI_ALL; // 访问全局常量 INI_ALL
$c = new \Exception('error'); // 实例化全局类 Exception
?>

PHP 命名空间的实现受到其语言自身的动态特征的影响,我们先来看一段代码:

<?php
class classname
{
  function __construct()
  {
    echo __METHOD__,"\n";
  }
}
function funcname()
{
  echo __FUNCTION__,"\n";
}
const constname = "global";
$a = 'classname';
$obj = new $a; // prints classname::__construct
$b = 'funcname';
$b(); // prints funcname
echo constant('constname'), "\n"; // prints global
?>

我们如果要将上述的代码转换到命名空间中,并且动态访问元素,就必须使用完全限定名称(包括命名空间前缀的类名称)。注意因为在动态的类名称、函数名称或常量名称中,限定名称和完全限定名称没有区别,因此其前导的反斜杠是不必要的。如下:

<?php
namespace namespacename;
class classname
{
  function __construct()
  {
    echo __METHOD__,"\n";
  }
}
function funcname()
{
  echo __FUNCTION__,"\n";
}
const constname = "namespaced";
include 'example1.php';
$a = 'classname';
$obj = new $a; // 输出 classname::__construct
$b = 'funcname';
$b(); // 输出函数名
echo constant('constname'), "\n"; // 输出 global
/* 如果使用双引号,使用方法为 "\\namespacename\\classname"*/
$a = '\namespacename\classname';
$obj = new $a; // 输出 namespacename\classname::__construct
$a = 'namespacename\classname';
$obj = new $a; // 输出 namespacename\classname::__construct
$b = 'namespacename\funcname';
$b(); // 输出 namespacename\funcname
$b = '\namespacename\funcname';
$b(); // 输出 namespacename\funcname
echo constant('\namespacename\constname'), "\n"; // 输出 namespaced
echo constant('namespacename\constname'), "\n"; // 输出 namespaced
?>

好啦,本次记录就到这里了,后续的记录会在之后的文章中有体现。

希望本文所述对大家PHP程序设计有所帮助。

PHP 相关文章推荐
PHP开发文件系统实例讲解
Oct 09 PHP
PHP获取163、gmail、126等邮箱联系人地址【已测试2009.10.10】
Oct 11 PHP
PHP数据集构建JSON格式及新数组的方法
Nov 07 PHP
Yii框架登录流程分析
Dec 03 PHP
WordPress中注册菜单与调用菜单的方法详解
Dec 18 PHP
php封装的smartyBC类完整实例
Oct 19 PHP
PHP基于反射机制实现插件的可插拔设计详解
Nov 10 PHP
PHP屏蔽关键字实现方法
Nov 17 PHP
php中简单的对称加密算法实现
Jan 05 PHP
php使用gd2绘制基本图形示例(直线、圆、正方形)
Feb 15 PHP
PHP编程计算两个时间段是否有交集的实现方法(不算边界重叠)
May 30 PHP
PHP开发中解决并发问题的几种实现方法分析
Nov 13 PHP
在 Laravel 6 中缓存数据库查询结果的方法
Dec 11 #PHP
PHP超级全局变量【$GLOBALS,$_SERVER,$_REQUEST等】用法实例分析
Dec 11 #PHP
关于PHP5.6+版本“No input file specified”问题的解决
Dec 11 #PHP
Laravel5.1 框架数据库操作DB运行原生SQL的方法分析
Jan 07 #PHP
Laravel5.1 框架表单验证操作实例详解
Jan 07 #PHP
PHP字符串与数组处理函数用法小结
Jan 07 #PHP
Laravel5.1 框架响应基本用法实例分析
Jan 04 #PHP
You might like
php+mysql事务rollback&amp;commit示例
2010/02/08 PHP
php中使用redis队列操作实例代码
2013/02/07 PHP
解析thinkphp import 文件内容变量失效的问题
2013/06/20 PHP
ThinkPHP之foreach标签使用概述
2014/06/30 PHP
PHP目录与文件操作技巧总结(创建,删除,遍历,读写,修改等)
2016/09/11 PHP
php实现当前页面点击下载文件的实例代码
2016/11/16 PHP
PHP日志LOG类定义与用法示例
2018/09/06 PHP
Javascript hasOwnProperty 方法 &amp; in 关键字
2008/11/26 Javascript
原来Jquery.load的方法可以一直load下去
2011/03/28 Javascript
alert和confirm功能介绍
2014/05/21 Javascript
JQuery拖动表头边框线调整表格列宽效果代码
2014/09/10 Javascript
jQuery制作网页版选项卡
2016/07/28 Javascript
jQuery实现的分页功能示例
2017/01/22 Javascript
Bootstrap导航简单实现代码
2017/03/06 Javascript
ionic2打包android时gradle无法下载的解决方法
2017/04/05 Javascript
微信小程序 slider的简单实例
2017/04/19 Javascript
js实现1,2,3,5数字按照概率生成
2017/09/12 Javascript
JavaScript面向对象的程序设计(犯迷糊的小羊)
2018/05/27 Javascript
ES6 系列之 Generator 的自动执行的方法示例
2018/10/19 Javascript
python开发之函数定义实例分析
2015/11/12 Python
Python编程中使用Pillow来处理图像的基础教程
2015/11/20 Python
详解Python设计模式编程中观察者模式与策略模式的运用
2016/03/02 Python
使用Python对MySQL数据操作
2017/04/06 Python
对python append 与浅拷贝的实例讲解
2018/05/04 Python
Python 中 function(#) (X)格式 和 (#)在Python3.*中的注意事项
2018/11/30 Python
Python比较配置文件的方法实例详解
2019/06/06 Python
Python 点击指定位置验证码破解的实现代码
2019/09/11 Python
python开发实例之Python的Twisted框架中Deferred对象的详细用法与实例
2020/03/19 Python
Python获取浏览器窗口句柄过程解析
2020/07/25 Python
Html5监听手机摇一摇事件的实现
2019/11/07 HTML / CSS
毕业生自荐信如何写
2014/03/24 职场文书
幸福家庭标语
2014/06/27 职场文书
计划生育个人总结
2015/03/02 职场文书
2015个人简历自我评价语
2015/03/11 职场文书
大学生心理健康教育心得体会
2016/01/12 职场文书
创业计划书之电动车企业
2019/10/11 职场文书