首頁 後端開發 php教程 PHP命名空间和自动加载类

PHP命名空间和自动加载类

Jun 07, 2016 pm 05:08 PM
php 載入 命名空間

PHP的命名空间(namespace)是php5.3之后才有的。这篇文章主要介绍了PHP命名空间和自动加载类的相关资料,需要的朋友可以参考下

PHP的命名空间(namespace)是php5.3之后才有的。这个概念在C#中已经很早就有了,php中的namespace其实和c#的概念是一样的。

为什么php中要使用namespace?

假设如果不使用namespace,那么每个类在一个项目中的名字就必须是固定的。因为php在new的时候不管是调用autoload还是调用已加载过的类,都存在一个类名对应的文件。所以在没有namespace的时候,我们会想各种命名规则来区分不同的类,比如project1_school1_class1_Student或者project2_school_class_Student。

引入namespace之后就可以将这个有效规避了,一个namespace就相当于对应一个文件路径,查找这个类的时候,就会去对应的文件路径查找类定义文件了。

背景

最近有个朋友问我 PHP 命名空间是咋样的,但是由于长期不做开发,笔者实际上也已经忘得差不多了,所以也回答不出来。只是记得和 Java 挺像的。事后重新查了一下 PHP 的官方文档,并且和 Java 做对比,Java 的命名空间实际上来自于 JVM 本身的机制,JVM 是基于 class 字节码文件加载类,由于类很容易出现重名的情况,换言之 class 字节码文件也会出现重名情况,所以就需要使用目录来管理不同的字节码文件,而为了保证加载正常,所以就需要命名空间这种机制。当然,也可以说是由于命名空间的存在才有了目录管理的方式。但是 PHP 和 Java 不一样,PHP 是一种动态脚本语言,它的代码分散在所有脚本中,当需要的时候才会使用 include 函数加载对应的文件,所以 PHP 的命名空间,实际上是基于 PHP 的自动加载类,自动加载类实现了才能保证 PHP 命名空间存在的意义。

命名空间概述

命名空间据笔者所知应该最早源于 C++ 语言,在 C++98 标准以后,为了保证各种命名不重合所推出的一种解决方案。现在的面向对象语言基本都有这种机制,当然除了命名空间以外,还有很多种方式,比如模块化,不过实际上这些机制都是用来解决封装问题的,所以笔者个人认为并无好坏之分。先把 PHP 官方文档代码拉出来溜溜

<?php
namespace my\name; // 参考 "定义命名空间" 小节
class MyClass {}
function myfunction() {}
const MYCONST = 1;
$a = new MyClass;
$c = new \my\name\MyClass; // 参考 "全局空间" 小节
$a = strlen(&#39;hi&#39;); // 参考 "使用命名空间:后备全局函数/常量" 小节
$d = namespace\MYCONST; // 参考 "namespace操作符和__NAMESPACE__常量” 小节
$d = __NAMESPACE__ . &#39;\MYCONST&#39;;
echo constant($d); // 参考 "命名空间和动态语言特征" 小节
?>
登入後複製

非常容易理解的代码,从上面的代码中可以看到 PHP 定义的命名空间是怎么样的,不过笔者个人认为其定义非常反人类,居然使用反斜杠来分隔命名空间路径。不过有一点需要注意,名为 PHP 或 php 的命名空间,以及以这些名字开头的命名空间(例如PHP\Classes)被保留用作语言内核使用,而不应该在用户空间的代码中使用。

定义命名空间

PHP 命名空间功能只能在 PHP5.3.0 以上版本使用,对于一个命名空间,只有类、接口、函数和常量会被包含在命名空间中。

<?php
namespace MyProject;
const CONNECT_OK = 1;
class Connection { /* ... */ }
function connect() { /* ... */ }
?>
登入後複製

当然,也可以使用花括号来包含所有需要的内容,就像这样。

<?php
declare(encoding=&#39;UTF-8&#39;);
namespace MyProject {
const CONNECT_OK = 1;
class Connection { /* ... */ }
function connect() { /* ... */ }
}
namespace { // 全局代码
session_start();
$a = MyProject\connect();
echo MyProject\Connection::start();
}
?>
登入後複製

不过这样很容易造成缩进上的问题,所以笔者不推荐使用,并且一般情况下,一个文件包含一个类,所以也不需要花括号来分割命名空间范围。

使用命名空间

对于命名空间路径来说,存在着三种形式

非限定名称,或者说不包含前缀的类名称。例如 $a=new foo(); 或 foo::staticmethod(); 。如果当前命名空间是 currentnamespace , foo 将被解析为 currentnamespace\foo 。如果使用 foo 的代码是全局的,不包含在任何命名空间中的代码,则 foo 会被解析为 foo`。

限定名称,或包含前缀的名称,例如 $a = new subnamespace\foo(); 或 subnamespace\foo::staticmethod(); 。如果当前的命名空间是 currentnamespace ,则 foo 会被解析为 currentnamespace\subnamespace\foo 。如果使用 foo 的代码是全局的,不包含在任何命名空间中的代码, foo 会被解析为 subnamespace\foo 。

完全限定名称,或包含了全局前缀操作符的名称,例如, $a = new \currentnamespace\foo(); 或 \currentnamespace\foo::staticmethod(); 。在这种情况下, foo 总是被解析为代码中的文字名 (literal name)currentnamespace\foo 。

由于 PHP 本身动态语言的特性,所以完全可以使用字符串动态访问命名空间内的元素。

<?php
namespace namespacename;
class classname
{
function __construct()
{
echo __METHOD__,"\n";
}
}
function funcname()
{
echo __FUNCTION__,"\n";
}
const constname = "namespaced";
include &#39;example1.php&#39;;
$a = &#39;classname&#39;;
$obj = new $a; // prints classname::__construct
$b = &#39;funcname&#39;;
$b(); // prints funcname
echo constant(&#39;constname&#39;), "\n"; // prints global
/* note that if using double quotes, "\\namespacename\\classname" must be used */
$a = &#39;\namespacename\classname&#39;;
$obj = new $a; // prints namespacename\classname::__construct
$a = &#39;namespacename\classname&#39;;
$obj = new $a; // also prints namespacename\classname::__construct
$b = &#39;namespacename\funcname&#39;;
$b(); // prints namespacename\funcname
$b = &#39;\namespacename\funcname&#39;;
$b(); // also prints namespacename\funcname
echo constant(&#39;\namespacename\constname&#39;), "\n"; // prints namespaced
echo constant(&#39;namespacename\constname&#39;), "\n"; // also prints namespaced
?>
登入後複製

不过有一点需要注意,就是单双引号之间的区别,单引号可以不需要处理 \ 的转译处理,而双引号就必须使用 \\ 等转译符号。

Java 语言使用 import 机制引入命名空间,由于 Java 可以指定到类名,所以 Java 最多只能导入到具体类,而 PHP 则可以指定到一个命名空间内的类、常量、方法等,并且支持命名空间别名。

<?php
namespace foo;
use My\Full\Classname as Another;
// 下面的例子与 use My\Full\NSname as NSname 相同
use My\Full\NSname;
// 导入一个全局类
use ArrayObject;
// importing a function (PHP 5.6+)
use function My\Full\functionName;
// aliasing a function (PHP 5.6+)
use function My\Full\functionName as func;
// importing a constant (PHP 5.6+)
use const My\Full\CONSTANT
$obj = new namespace\Another; // 实例化 foo\Another 对象
$obj = new Another; // 实例化 My\Full\Classname 对象
NSname\subns\func(); // 调用函数 My\Full\NSname\subns\func
$a = new ArrayObject(array(1)); // 实例化 ArrayObject 对象
// 如果不使用 "use \ArrayObject" ,则实例化一个 foo\ArrayObject 对象
func(); // calls function My\Full\functionName
echo CONSTANT; // echoes the value of My\Full\CONSTANT
?>
登入後複製

名称解析规则

首先就是前面讲过的三种名称类型,名称解析遵循以下规则:

对完全限定名称的函数,类和常量的调用在编译时解析。例如 new \A\B 解析为类 A\B。

所有的非限定名称和限定名称(非完全限定名称)根据当前的导入规则在编译时进行转换。例如,如果命名空间 A\B\C 被导入为 C,那么对 C\D\e() 的调用就会被转换为 A\B\C\D\e()。

在命名空间内部,所有的没有根据导入规则转换的限定名称均会在其前面加上当前的命名空间名称。例如,在命名空间 A\B 内部调用 C\D\e(),则 C\D\e() 会被转换为 A\B\C\D\e() 。

非限定类名根据当前的导入规则在编译时转换(用全名代替短的导入名称)。例如,如果命名空间 A\B\C 导入为C,则 new C() 被转换为 new A\B\C() 。

在命名空间内部(例如A\B),对非限定名称的函数调用是在运行时解析的。例如对函数 foo() 的调用是这样解析的:

在当前命名空间中查找名为 A\B\foo() 的函数

尝试查找并调用 全局(global) 空间中的函数 foo()。

在命名空间(例如A\B)内部对非限定名称或限定名称类(非完全限定名称)的调用是在运行时解析的。下面是调用 new C() 及 new D\E() 的解析过程:

new C()的解析:

在当前命名空间中查找A\B\C类。

尝试自动装载类A\B\C。

new D\E()的解析:

在类名称前面加上当前命名空间名称变成:A\B\D\E,然后查找该类。

尝试自动装载类 A\B\D\E。

为了引用全局命名空间中的全局类,必须使用完全限定名称 new \C()。

从上面的规则来看,实际上 PHP 的导入规则和 Java 有点类似,但是却有不一样,主要是因为 Java 是完全面向对象的,而 PHP 本质上还只是一种基于对象的语言。

自动加载类

在早期 PHP 开发中,开发者最烦的就是一堆 include 函数包含了一大堆文件,而且早期时候 PHP 面向对象的概念确实太差了,因为 PHP 作为一种脚本语言,不存在程序入口,所以脚本顺序化执行的诱惑力实在是很大,即使面向对象开发,但是缺少极佳的模块划分导入机制,代码可以说很难有美感,最大的代表就是 Wordpress。如果有朋友看过这个典型项目,可以觉得非常痛苦,因为各种初始化、业务流程都分散在各个不同的文件中,使用 include 函数进行衔接,然后每次页面渲染都是同样的要走一趟流程。当然,这是 Wordpress 的历史包袱,而在支持老版本 PHP 的情况下 Wordpress 代码已经写得足够优化了。

在 PHP5 中就不需要这么麻烦了,因为可以定义一个 __autoload() 函数,当调用一个未定义的类的时候就会启动此函数,从而在抛出错误之前做最后的补救,不过这个函数的本意已经被完全曲解使用了,现在都用来做自动加载。

注意,这个函数实际上已经不被推荐使用了,相反,现在应当使用 spl_autoload_register() 来注册类的自动加载函数。

bool spl_autoload_register ([ callable $autoload_function [, bool $throw = true [, bool $prepend = false ]]] )
autoload_function 是需要注册的自动装载函数,如果此项为空,则会注册 spl_autoload 函数,

throw 此参数设置了 autoload_function 无法成功注册时, spl_autoload_register() 是否抛出异常。

prepend 如果是 true, spl_autoload_register() 会添加函数到队列之首,而不是队列尾部。

上面提到了 spl_autoload 函数,实际上注册函数的规范就应当遵循此函数,函数声明如下:

void spl_autoload ( string $class_name [, string $file_extensions ] )
由于这个函数默认实现是通过 C 语言,所以这里给出一个 PHP 语言的实现规范。

<?php
// Your custom class dir
define(&#39;CLASS_DIR&#39;, &#39;class/&#39;)
// Add your class dir to include path
set_include_path(get_include_path().PATH_SEPARATOR.CLASS_DIR);
// You can use this trick to make autoloader look for commonly used "My.class.php" type filenames
spl_autoload_extensions(&#39;.class.php&#39;);
// Use default autoload implementation
spl_autoload_register();
?>
登入後複製

大致上就和这个是类似的。实际上命名空间和自动加载类的结合就基本是通过路径形式

function __autoload(){
$dir = &#39;./libralies&#39;;
set_include_path(get_include_path(). PATH_SEPARATOR. $dir);
$class = str_replace(&#39;\\&#39;, &#39;/&#39;, $class) . &#39;.php&#39;; 
require_once($class);
}
登入後複製

将命名空间路径替换为实际路径。

以上内容是小编给大家介绍的PHP命名空间和自动加载类,希望对大家有所帮助!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

<🎜>:泡泡膠模擬器無窮大 - 如何獲取和使用皇家鑰匙
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
北端:融合系統,解釋
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
Mandragora:巫婆樹的耳語 - 如何解鎖抓鉤
3 週前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

熱門話題

Java教學
1666
14
CakePHP 教程
1426
52
Laravel 教程
1328
25
PHP教程
1273
29
C# 教程
1253
24
PHP和Python:比較兩種流行的編程語言 PHP和Python:比較兩種流行的編程語言 Apr 14, 2025 am 12:13 AM

PHP和Python各有優勢,選擇依據項目需求。 1.PHP適合web開發,尤其快速開發和維護網站。 2.Python適用於數據科學、機器學習和人工智能,語法簡潔,適合初學者。

PHP:網絡開發的關鍵語言 PHP:網絡開發的關鍵語言 Apr 13, 2025 am 12:08 AM

PHP是一種廣泛應用於服務器端的腳本語言,特別適合web開發。 1.PHP可以嵌入HTML,處理HTTP請求和響應,支持多種數據庫。 2.PHP用於生成動態網頁內容,處理表單數據,訪問數據庫等,具有強大的社區支持和開源資源。 3.PHP是解釋型語言,執行過程包括詞法分析、語法分析、編譯和執行。 4.PHP可以與MySQL結合用於用戶註冊系統等高級應用。 5.調試PHP時,可使用error_reporting()和var_dump()等函數。 6.優化PHP代碼可通過緩存機制、優化數據庫查詢和使用內置函數。 7

PHP行動:現實世界中的示例和應用程序 PHP行動:現實世界中的示例和應用程序 Apr 14, 2025 am 12:19 AM

PHP在電子商務、內容管理系統和API開發中廣泛應用。 1)電子商務:用於購物車功能和支付處理。 2)內容管理系統:用於動態內容生成和用戶管理。 3)API開發:用於RESTfulAPI開發和API安全性。通過性能優化和最佳實踐,PHP應用的效率和可維護性得以提升。

PHP與Python:了解差異 PHP與Python:了解差異 Apr 11, 2025 am 12:15 AM

PHP和Python各有優勢,選擇應基於項目需求。 1.PHP適合web開發,語法簡單,執行效率高。 2.Python適用於數據科學和機器學習,語法簡潔,庫豐富。

PHP的持久相關性:它還活著嗎? PHP的持久相關性:它還活著嗎? Apr 14, 2025 am 12:12 AM

PHP仍然具有活力,其在現代編程領域中依然佔據重要地位。 1)PHP的簡單易學和強大社區支持使其在Web開發中廣泛應用;2)其靈活性和穩定性使其在處理Web表單、數據庫操作和文件處理等方面表現出色;3)PHP不斷進化和優化,適用於初學者和經驗豐富的開發者。

PHP與其他語言:比較 PHP與其他語言:比較 Apr 13, 2025 am 12:19 AM

PHP適合web開發,特別是在快速開發和處理動態內容方面表現出色,但不擅長數據科學和企業級應用。與Python相比,PHP在web開發中更具優勢,但在數據科學領域不如Python;與Java相比,PHP在企業級應用中表現較差,但在web開發中更靈活;與JavaScript相比,PHP在後端開發中更簡潔,但在前端開發中不如JavaScript。

PHP和Python:代碼示例和比較 PHP和Python:代碼示例和比較 Apr 15, 2025 am 12:07 AM

PHP和Python各有優劣,選擇取決於項目需求和個人偏好。 1.PHP適合快速開發和維護大型Web應用。 2.Python在數據科學和機器學習領域佔據主導地位。

PHP和Python:解釋了不同的範例 PHP和Python:解釋了不同的範例 Apr 18, 2025 am 12:26 AM

PHP主要是過程式編程,但也支持面向對象編程(OOP);Python支持多種範式,包括OOP、函數式和過程式編程。 PHP適合web開發,Python適用於多種應用,如數據分析和機器學習。

See all articles