iT邦幫忙

2023 iThome 鐵人賽

DAY 21
0
DevOps

嘿,稍等一下!別急著開發功能,先來打造 Walking Skeleton 吧!系列 第 21

【Walking Skeleton】Day21 - 命名空間 namespace 和 use 是做什麼用的?

  • 分享至 

  • xImage
  •  

沒有 namespace 的時候

有一個專案 school 和兩個函式庫 lib_a、lib_b,好死不死這兩個函式庫中的 class 名稱是一樣的,都叫做 Student,但是功能不太一樣,兩個都要用到,別人寫的函式庫改不了阿,那只好硬著頭皮希望他能跑了

school 專案的目錄結構

school
├─lib_a
│  └─Student.php
├─lib_b
│  └─Student.php
└─index.php

lib_a/Student.php 和 lib_b/Student.php 的程式

class Student {
    public function __construct(
        public int $id,
        public string $name,
    ) {
    }
    // ...
}

index.php 的程式

require __DIR__ . '/lib_a/Student.php';
require __DIR__ . '/lib_b/Student.php';

$student = new Student(1, 'John');

echo 'success';

執行看看

$ php "d:\_code\php\school\index.php"

Fatal error: Cannot declare class Student, because the name is already in use in D:\_code\php\school\lib_b\Student.php on line 3

Call Stack:
    0.0003     366088   1. {main}() D:\_code\php\school\index.php:0
    0.0101     366672   2. require('D:\_code\php\school\lib_b\Student.php') D:\_code\php\school\index.php:4

果不其然炸掉了,有兩個 Student 怎麼可能知道要 new 哪一個,不過是在更前面 require 載入檔案時就掛了,並且錯誤訊息說:「這個 Student 名稱被用過了,你換一個吧」


有了 namespace 的話

現在有了 namespace,各家的函式庫可以指定自己的 class 或 function 是屬於哪裡的,用法也很簡單,在檔案的開頭設定 namespace 就行了,使用時在 class 前多加它的 namespace,可以想像成檔案的目錄,通常也會跟檔案目錄有對應

school 專案的目錄結構

school
├─lib_a
│  └─Student.php
├─lib_b
│  └─Student.php
└─index.php

lib_a/Student.php 的程式

namespace lib_a;

class Student {
    public function __construct(
        public int $id,
        public string $name,
    ) {
    }
    // ...
}

lib_b/Student.php 的程式

namespace lib_b;

class Student {
    public function __construct(
        public int $id,
        public string $name,
    ) {
    }
    // ...
}

index.php 的程式

require __DIR__ . '/lib_a/Student.php';
require __DIR__ . '/lib_b/Student.php';

$student1 = new \lib_a\Student(1, 'John');
$student2 = new \lib_b\Student(1, 'Adam');

echo 'success';

再執行看看

$ php "d:\_code\php\school\index.php"
success

這次就沒問題了,namespace 真是幫了個大忙,以後再也不用擔心函式庫名稱衝突的問題了


那 use 是做什麼用的?

use 有三種用法,所以先再新增一個 lib_c,還有在 index 載入 lib_c

school 專案的目錄結構

school
├─lib_a
│  └─Student.php
├─lib_b
│  └─Student.php
├─lib_c
│  └─members
│    └─Student.php
└─index.php

lib_c/members/Student.php 的程式

namespace lib_c\members;

class Student {
    public function __construct(
        public int $id,
        public string $name,
    ) {
    }
    // ...
}

index.php 的程式

require __DIR__ . '/lib_a/Student.php';
require __DIR__ . '/lib_b/Student.php';
require __DIR__ . '/lib_c/members/Student.php';

use lib_a\Student;
use lib_b\Student as BStudent;
use lib_c\members;

$student1 = new Student(1, 'John');
$student2 = new BStudent(1, 'Adam');
$student3 = new members\Student(1, 'Yuna');

echo 'success';

再執行看看

$ php "d:\_code\php\school\index.php"
success

use 是用建立別名的,讓程式中不會塞進一堆 namespace

  1. lib_a\Student
    namespace + class 名稱,自動使用 class 名稱作為別名,在 new 物件的時候只需要輸入 class 名稱就可以了,這個也是最常見的用法
  2. lib_b\Student as BStudent
    namespace + class 名稱,並且用 as 指定一個名稱,因為 Student 已經被用過了,所以另外取名叫做 BStudent,在 new 物件的時候用另外取的別名 BStudent 來建立物件
  3. lib_c\members
    只有 namespace,這樣就會變成 members 是 lib_c\members 的別名,在 new 物件的時候還是需要加上 namespace,會大量用到同個 namespace 的 class 時就會考慮這樣寫
  4. lib_c\members as m
    其實還有第四種,就是 namespace 也可以用 as 指定一個名稱,不過比較少看到有人會這樣用就是了

namespace 和 use 很簡單吧 (比起前面那些 SSH 來 SSH 去的東西),相信你很快也能上手


上一篇
【Walking Skeleton】Day20 - 連自己連線進去 git pull 都懶嗎?交給 Github Actions 幫你做吧!
下一篇
【Walking Skeleton】Day22 - 安裝 Composer 讓 autoload 來幫你自動 require 函式庫吧!
系列文
嘿,稍等一下!別急著開發功能,先來打造 Walking Skeleton 吧!34
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言