# :-: 一、命名空間的作用
* 解決全局成員的命名沖突問題
* 全局成員: 類 / 函數 / 常量
```php
// 命名空間的作用與適用對象
require 'funciton.php';
function func($a, $b){
return $a.' + '.$b.' = '.($a+$b);
}
// 直接調用會出現函數未定義錯誤
echo func(10, 20);
// 如果想訪問外部加載的函數func,就要帶上命名空間
echo \my\func(10, 20);
// 而如果還想訪問在當前腳本中定義的函數func,也要用命名空間訪問
echo \func(10,20);
```
```php
// 1、使用較長的命名來進行區分
function my_func($a, $b)
{
return $a.' * '.$b.' = '.($a*$b);
}
// 2、使用命名空間, 不改變原來的函數名稱
namespace my;
function func($a, $b)
{
return $a.' * '.$b.' = '.($a*$b);
}
```
* 命名空間解決了什么問題呢?
* php 全局成員的命名沖突的問題
* 全局成員, 是指在當前腳本中,并不受使用域的限制,總是可以訪問的
* php 中哪些是全局成員呢? 類, 函數, 常量
* 因為這三個成員, 不受作用域的限制, 所以無法像變量那樣,用作用域對他們的可見性進行區隔
* 所以對于全局成員, 我們之前是通過一個很長的名稱來進行區分, 例如: my_func, 難寫難記
* 使用命名空間, 可以防止命名恐懼癥, 在開發中可以使用相同名稱的全局成員,只要放在不同的空間中即可
*****
# :-: 二、命名空間的定義
* `namespace`: 創建命名空間, 必須是腳本的第一行代碼
* 在一個腳本中定義多個命名空間與成員(除全局空間)
```php
namespace one;
// 在one空間中定義三個全局成員
class Pig {}
function hello(){ return 'Hello 歐陽克'; }
const SITE = '白駝山莊';
// 訪問成員
echo Pig::class . '<br>'; // 完整類名
echo hello() . '<br>';
echo SITE . '<hr>';
```
> 兩個命名空間
```php
namespace one;
// 在one空間中定義三個全局成員
class Pig {}
function hello(){ return 'Hello 歐陽克'; }
const SITE = '白駝山莊';
// 訪問成員
echo Pig::class . '<br>'; // 完整類名
echo hello() . '<br>';
echo SITE . '<hr>';
namespace two;
class Pig {}
function hello(){ return 'Hello 黃蓉'; }
const SITE = '桃花島';
echo Pig::class . '<br>'; // 完整類名
echo hello() . '<br>';
echo SITE . '<br>';
```
> 訪問另一個域名空間
```php
// 如果要在當前空間下面, 訪問其它空間的成員, 例如one空間
// 與文件系統類似,從根空間開始,根空間: "\"
echo '<br>';
echo \one\Pig::class . '<br>'; // 完整類名
echo \one\hello() . '<br>';
echo \one\SITE . '<hr>';
```
* 盡管可以在一個腳本中, 可以聲明多個命名空間,但并不推薦這樣去做
* 使用本例的方法, 在同一個腳本中聲明多個空間,但無法自定義根空間成員,只能調用
*****
# :-: 三、同時定義多個空間
* `namespace {}`: 用大括號在一個腳本中聲明多個命名空間
```php
namespace one{
class Pig {}
function hello(){ return 'Hello 歐陽克'; }
const SITE = '白駝山莊';
// 訪問成員
echo Pig::class . '<br>'; // 完整類名
echo hello() . '<br>';
echo SITE . '<hr>';
}
namespace two{
class Pig {}
function hello(){ return 'Hello 黃蓉'; }
const SITE = '桃花島';
echo Pig::class . '<br>'; // 完整類名
echo hello() . '<br>';
echo SITE . '<br>';
// 在空間two中訪問one空間
echo '<br>';
echo \one\Pig::class . '<br>'; // 完整類名
echo \one\hello() . '<br>';
echo \one\SITE . '<hr>';
}
// 定義全局空間, 空間名稱為空,表示全局空間
namespace{
class Pig {}
function hello(){ return 'Hello 郭靖'; }
const SITE = '襄陽';
}
namespace three{
// 調用全局成員
echo \Pig::class . '<br>'; // 完整類名
echo \hello() . '<br>';
echo \SITE;
}
```
*****
# :-: 四、子命名空間
* `namespace`: 引用當前命名空間
* `__NAMESPACE__`: 當前空間名稱字符串(魔術常量)
* `one\two\three\...\ClassName`: 類空間的分層管理,命名空間是可以分層管理的
```php
namespace think;
class Dog {}
echo Dog::class . '<hr>';
// 雙下劃線開頭的魔方常量, 所謂魔術是指,盡管是常量,但可以隨作用域發生變化
echo __NAMESPACE__ . '<br>';
namespace think\admin;
echo __NAMESPACE__ . '<br>';
class Dog {}
echo Dog::class . '<hr>';
// 如果我想訪問空間:think\admin\model\Dog類
// 可以將當前空間看成當前目錄,用關鍵字namespace來引用當前空間
echo namespace\model\Dog::class . '<hr>';
namespace think\admin\model;
echo __NAMESPACE__ . '<br>';
class Dog {}
echo Dog::class . '<hr>';
```
*****
# :-: 五、空間的類文件自動加載技術
* `str_replace()`: 字符串替換函數,將空間分隔符替換成路徑分隔符
* `DIRECTORY_SEPARATOR`: 路徑分隔符常量
* `spl_autoload_register()`: 自動加載函數
```php
// 傳統方式
require 'inc/Class1.php';
require 'inc/Class2.php';
$obj1 = new inc\Class1();
$obj2 = new inc\Class2();
echo get_class($obj1) . '<br>';
echo get_class($obj2) . '<br>';
echo '<hr>';
```
> Class1.php
```php
<?php
namespace inc;
class Class1
{
}
```
> Class2.php
```php
<?php
namespace inc;
class Class2
{
}
```
> 自動加載技術
```php
spl_autoload_register(function ($class){
// 這里將"\"替換成路徑分隔符, 推薦使用常量:DIRECTORY_SEPARATOR,而不是"/",可苑跨平臺支持
$path = str_replace('\\', DIRECTORY_SEPARATOR, $class);
// 相對路徑
// $path = $path . '.php';
// 絕對路徑
$path = __DIR__ . '/' . $path . '.php';
// 不是文件或文件不存在,則拋出異常
if (!(is_file($path) && file_exists($path))) {
throw new \Exception('不是文件或文件不存在');
}
require $path;
});
$obj1 = new inc\Class1();
$obj2 = new inc\Class2();
echo get_class($obj1) . '<br>';
echo get_class($obj2) . '<br>';
```
*****
# :-: 六、空間別名
* `use namespace/className`: 通過`use`關鍵字導入空間別名
* 為較長的類名提供一種簡化方案
* 導入空間別名默認從全局空間開始
* 導入空間別名, 不能代替外部文件的加載
* 注意很多框架采用了自動加載技術,會導致一些同學誤以后use可以加載類
* `as`: 解決導入的類別名與當前空間類重名問題
```php
namespace current;
include 'inc/Class1.php';
// 如果要使用Class1類,需要先實例化
$obj = new \inc\Class1();
echo get_class($obj) . '<br>';
echo '<hr>';
# 你會發現,這樣的類名有點長了, 實際開發過程中, 比這個長的多的是
# 如何來簡化呢? 使用別名導入
use \inc\Class1 AS C1;
// 現在就簡單多了,其實使用use導入類別名時, 默認就是根空間(全局)開始
// 所以 "\"可以省略, 實際上也不推薦加上
// use \inc\Class1 AS C1;
// 如果當前腳本中沒有與導入的類名沖突的類, 就沒必要用AS 起一個別名了
class Class1{};
// 此時的類的默認別名, 就是原來的名字: Class1
// use \inc\Class1;
// $obj = new C1();
$obj = new Class1();
echo get_class($obj) . '<br>';
```
*****
# :-: 七、命名空間實戰
```php
namespace db;
// 連接數據庫: 目前在空間中寫代碼, PDO類中全局中, 建議加上"\"
$pdo = new \PDO('mysql:host=localhost;dbname=ouyangke','root','root');
// 如果PDO類前不加"\"也不會報錯, 因為系統在當前空間中沒有找到,會自動轉到全局中查找, 為提升查詢效率,強烈建議加上
//查詢點數據展示出來,以測試數據庫操作正確
$stmt = $pdo->prepare('SELECT `id`,`name`,`position` FROM `staff` LIMIT :offset, :num');
$stmt->bindValue('offset',0, \PDO::PARAM_INT);
$stmt->bindValue('num',5, \PDO::PARAM_INT);
$stmt->execute();
// 將結果集中的列綁定到變量
$stmt->bindColumn('id', $id);
$stmt->bindColumn('name', $name);
$stmt->bindColumn('position', $position);
// 遍歷
while ($stmt->fetch(\PDO::FETCH_BOUND)) {
echo "<li>{$id}. {$name} : {$position}</li>";
}
```
- 序言
- PHP基礎
- 認識PHP
- 環境安裝
- PHP語法
- 流程控制
- PHP數組
- PHP函數
- PHP類與對象
- PHP命名空間
- PHP7新特性
- PHP方法庫
- PHP交互
- 前后端交互
- 項目常規開發流程
- MySQL數據庫
- 會話控制
- Ajax分頁技術
- 細說函數
- 類與對象
- 對象進階
- 類與對象進階
- OOP面向對象
- 設計模式
- 路由與模板引擎
- 異常類
- PHP爬蟲
- PHP抓取函數
- PHP匹配函數
- 正則表達式
- PHP字符串函數
- 抓取實戰
- PHP接口
- 了解接口
- PHP插件
- PHPSpreadsheet
- ThinkPHP6
- 安裝
- 架構
- 數據庫
- 數據庫操作
- 視圖
- 模版
- 模型
- 雜項
- 命令行
- 交互
- 微信小程序
- 介紹
- 配置
- 組件
- 交互
- API
- 其他知識
- 百度小程序
- 介紹
- 配置
- 組件
- 交互
- API
- 其他知識
- Linux
- 服務器上線流程
- 安裝svn
- MySQL
- 認識MySQL
- MySQL函數
- 雜項
- composer依賴管理工具