搜尋
首頁後端開發php教程PHP命名空間與自動載入類

PHP命名空間與自動載入類

Jul 29, 2016 am 08:54 AM
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
超越炒作:評估當今PHP的角色超越炒作:評估當今PHP的角色Apr 12, 2025 am 12:17 AM

PHP在現代編程中仍然是一個強大且廣泛使用的工具,尤其在web開發領域。 1)PHP易用且與數據庫集成無縫,是許多開發者的首選。 2)它支持動態內容生成和麵向對象編程,適合快速創建和維護網站。 3)PHP的性能可以通過緩存和優化數據庫查詢來提升,其廣泛的社區和豐富生態系統使其在當今技術棧中仍具重要地位。

PHP中的弱參考是什麼?什麼時候有用?PHP中的弱參考是什麼?什麼時候有用?Apr 12, 2025 am 12:13 AM

在PHP中,弱引用是通過WeakReference類實現的,不會阻止垃圾回收器回收對象。弱引用適用於緩存系統和事件監聽器等場景,需注意其不能保證對象存活,且垃圾回收可能延遲。

解釋PHP中的__ Invoke Magic方法。解釋PHP中的__ Invoke Magic方法。Apr 12, 2025 am 12:07 AM

\_\_invoke方法允許對象像函數一樣被調用。 1.定義\_\_invoke方法使對象可被調用。 2.使用$obj(...)語法時,PHP會執行\_\_invoke方法。 3.適用於日誌記錄和計算器等場景,提高代碼靈活性和可讀性。

解釋PHP 8.1中的纖維以進行並發。解釋PHP 8.1中的纖維以進行並發。Apr 12, 2025 am 12:05 AM

Fibers在PHP8.1中引入,提升了並發處理能力。 1)Fibers是一種輕量級的並發模型,類似於協程。 2)它們允許開發者手動控制任務的執行流,適合處理I/O密集型任務。 3)使用Fibers可以編寫更高效、響應性更強的代碼。

PHP社區:資源,支持和發展PHP社區:資源,支持和發展Apr 12, 2025 am 12:04 AM

PHP社區提供了豐富的資源和支持,幫助開發者成長。 1)資源包括官方文檔、教程、博客和開源項目如Laravel和Symfony。 2)支持可以通過StackOverflow、Reddit和Slack頻道獲得。 3)開發動態可以通過關注RFC了解。 4)融入社區可以通過積極參與、貢獻代碼和學習分享來實現。

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

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

php:死亡還是簡單地適應?php:死亡還是簡單地適應?Apr 11, 2025 am 12:13 AM

PHP不是在消亡,而是在不斷適應和進化。 1)PHP從1994年起經歷多次版本迭代,適應新技術趨勢。 2)目前廣泛應用於電子商務、內容管理系統等領域。 3)PHP8引入JIT編譯器等功能,提升性能和現代化。 4)使用OPcache和遵循PSR-12標準可優化性能和代碼質量。

PHP的未來:改編和創新PHP的未來:改編和創新Apr 11, 2025 am 12:01 AM

PHP的未來將通過適應新技術趨勢和引入創新特性來實現:1)適應云計算、容器化和微服務架構,支持Docker和Kubernetes;2)引入JIT編譯器和枚舉類型,提升性能和數據處理效率;3)持續優化性能和推廣最佳實踐。

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

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

AI Clothes Remover

AI Clothes Remover

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

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
3 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
3 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您聽不到任何人,如何修復音頻
3 週前By尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解鎖Myrise中的所有內容
4 週前By尊渡假赌尊渡假赌尊渡假赌

熱工具

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SecLists

SecLists

SecLists是最終安全測試人員的伙伴。它是一個包含各種類型清單的集合,這些清單在安全評估過程中經常使用,而且都在一個地方。 SecLists透過方便地提供安全測試人員可能需要的所有列表,幫助提高安全測試的效率和生產力。清單類型包括使用者名稱、密碼、URL、模糊測試有效載荷、敏感資料模式、Web shell等等。測試人員只需將此儲存庫拉到新的測試機上,他就可以存取所需的每種類型的清單。

PhpStorm Mac 版本

PhpStorm Mac 版本

最新(2018.2.1 )專業的PHP整合開發工具

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

強大的PHP整合開發環境

SublimeText3 Linux新版

SublimeText3 Linux新版

SublimeText3 Linux最新版