1、命名空间
1.1、理解全局成员
// 全局成员共有四个: 函数, 常量, 类/接口(函数外部声明)
// 1、函数
function demo() {}
// 2、常量
const USER_NAME = 'Peter Zhu';
// 3、类
class User {}
// 4、接口
interface iDb {}
// 全局成员最大特点:全局可见 / 最大缺点: 不能重复命名
1.2、命名空间的定义
1、命名空间使用
namespace
关键字定义,语法如下:
namespace project1;
namespace project2;
namespace project3;
一般情况下,不推荐单个文件中定义多个命名空间,如果需要,可以使用大括号进行定义:
namespace project1
{
}
namespace project2
{
}
namespace project3
{
}
1.3、命名空间的访问
非同一命名空间的访问,需指定要访问的命名空间名称
一旦定义命名空间,命名空间{}之外不能存在任何代码
namespace project1
{
// 接口
interface iTest {
public function getSite();
}
// 类
class Demo implements iTest
{
public function getSite()
{
return 'php中文网';
}
}
// 函数
function f1(iTest $obj) {
return $obj->getSite();
}
// 常量
const SITE_NAME='php中文网';
//命名空间内访问:
echo (new Demo)->getSite().'<br>';
echo f1(new Demo).'<br>';
echo SITE_NAME.'<br>';
}
//-------------------------------------------------------------
// 注意:一旦定义命名空间,命名空间{}之外不能存在任何代码
// echo (new Demo)->getSite().'<br>';
// echo f1(new Demo).'<br>';
// echo SITE_NAME.'<br>';
//报错:Fatal error: No code may exist outside of namespace {}
//-------------------------------------------------------------
namespace project2
{
//在project2访问project1内容:
echo '<hr>';
//方法访问:示例化对象时加上要访问的命名空间名称
echo (new \project1\Demo)->getSite().'<br>';
//函数访问:函数前及示例化对象时都要加上要访问的命名空间名称
echo \project1\f1(new \project1\Demo).'<br>';
//常量访问:常量前加上要访问的命名空间名称
echo \project1\SITE_NAME.'<br>';
// “\”表示全局“路径”,相当于根目录位置开始
}
1.4、命名空间使用
非限定名称: 总是从全局空间开始, 前面总是一个: “\” , “\A\B…”
限定名称:类名总是会有一个或多个空间名称,但不是从全局开始, “A\B…”
完全限定名称:就是不带有空间名称的类,如当前命名空间的类。
namespace project1
{
class T1 {}
}
namespace project2
{
class T1 {}
}
namespace project3
{
class T1 {}
}
namespace demo\project
{
class T1 {}
}
namespace demo
{
class T1 {}
// 1. 完全限定名称的类名:\project1\T1 ,类似绝对路径
echo \project1\T1::class, '<br>';
echo \project2\T1::class, '<br>';
echo \project3\T1::class, '<hr>';
// 2. 限定名称的类名: demo\project 理解成相对路径(当前命名空间下的下一级可以省略当前命名空间)
echo project\T1::class, '<hr>';
// 3. 非限定名称的类:
echo T1::class, '<hr>';
}
1.5、命名空间的别名
namespace project1
{
class T1 {}
}
namespace project2
{
class T1 {}
}
namespace demo
{
// 1、非别名访问
echo \project1\T1::class, '<br>';
echo \project2\T1::class, '<hr>';
// 2、别名访问
use \project1\T1 AS P1;
use \project2\T2 AS P2;
echo P1::class, '<br>';
echo P2::class, '<hr>';
}
namespace demo1
{
class T1 {}
// 3、如果当前类中也有一个与之同名的非限定的类,就不能省略别名
use \project1\T1 AS PT1;
echo PT1::class, '<br>';
echo T1::class, '<hr>';
}
2、类的加载
如demo.php目录下有以下几个类文件:
#inc/lib/Test1.php
// 当前类的命名空间与当前类的文件路径对应起来
namespace inc\lib;
// 类名必须与当前类文件名称相同
class Test2 {}
function show(){
return 'PHP中文网';
}
#inc/lib/Test2.php
namespace inc\lib;
class Test2 {}
#inc/lib/Test3.php
namespace inc\lib;
class Test3 {}
2.1、手动加载
# demo.php
require 'inc/lib/Test1.php';
require 'inc/lib/Test2.php';
require 'inc/lib/Test3.php';
var_dump(new inc\lib\Test1());
echo '<br>';
var_dump(new inc\lib\Test2());
echo '<br>';
var_dump(new inc\lib\Test3());
如果一个php文件里需要引用更多对象,那么这个文件就需要使用include或require逐个引用,于是就可以使用自动加载。
2.2、自动加载
# demo.php
function classLoader($class)
{
// DIRECTORY_SEPARATOR 可以随操作系统不同,使用不同的目录分隔符
//1、获取文件名(替换目录分隔符)
// $path = str_replace('\\', '/', '\inc\lib\Test1' );
$path = str_replace('\\', DIRECTORY_SEPARATOR, $class);
//2、获取文件名完整路径(替换目录分隔符)
$file = __DIR__ . DIRECTORY_SEPARATOR . $path . '.php';
//3、检测文件是否存在,存在则引入
if (file_exists($file)) {
require_once $file;
//equire()与require_once()的区别
// require()会在每一处出现调用的地方都重新调用(加载文件)。
// require_once() 指定的文件如果已经被包含过,则不会再次包含。它可以避免函数重定义,变量重新赋值等问题。
}
}
try {
spl_autoload_register('classLoader');
}catch (Exception $e){
die($e->getMessage());
}
var_dump(new inc\lib\Test1());
echo '<br>';
var_dump(new inc\lib\Test2());
echo '<br>';
var_dump(new inc\lib\Test3());
//实例化对象可以使用use引用以缩短代码可读性
use inc\lib\Test1;
var_dump(new Test1());
使用匿名函数实现:
try {
spl_autoload_register(function($class){
$path = str_replace('\\', DIRECTORY_SEPARATOR, $class);
$file = __DIR__ . DIRECTORY_SEPARATOR . $path . '.php';
if (file_exists($file)) {
require_once $file;
}
});
} catch (Exception $e) {
die($e->getMessage());
}
// 通过实例化自动加载inc\lib\Test1.php
new inc\lib\Test1();
// 输出inc\lib\Test1.php中的函数
echo \inc\lib\show();
echo '<br>';
var_dump(new inc\lib\Test1());
echo '<br>';
var_dump(new inc\lib\Test2());
echo '<br>';
var_dump(new inc\lib\Test3());
总结
1、全局成员共有四个: 函数, 常量, 类/接口(函数外部声明);
2、命名空间使用:namespace 空间名;
或 namespace 空间名{}
定义;
3、对命名空间的访问和使用有了初步理解;
4、类的加载需要include
或require
手动引入类文件,使用spl_autoload_register()
可以实现自动加载,通过验证,自动加载后函数也可以自动加载并访问。