PHP的SPL擴展庫(四)函數

今天我們繼續來學習 SPL 中的內容,這篇文章的內容是比較簡單的關於 SPL 中所提供的一系列函數相關的內容。其實在之前的不少文章中我們都已經接觸過一些 SPL 中提供的函數了。這次我們就詳細地再好好學習一下。

類信息相關函數
類信息相關的函數主要都是查看一些類的信息的函數,並沒有什麼操作類功能的函數。

類的繼承、接口、特性查看
首先,我們來看一下,如果想要獲得當前類實現了哪個接口,那麼我們就直接使用一個 class_implements() 就可以了。

interface A {}
interface B {}

class TestA implements A,B {}

var_dump(class_implements(new TestA));
// array(2) {
//     ["A"]=>
//     string(1) "A"
//     ["B"]=>
//     string(1) "B"
//   }

可以看到,它返回的是一個數組,顯示的就是我們當前這個類對象所實現的接口名稱。如果我們查詢的類沒有實現任何接口,那麼它返回的就是空的數組。

var_dump(class_implements(new stdClass()));
// array(0) {
// }

同樣,我們還可以查看某個類對象的父類。

class C{}

class TestB extends C {}

var_dump(class_parents(new TestB));
// array(1) {
//     ["C"]=>
//     string(1) "C"
//   }

雖說 PHP 是單繼承型的語言,但使用 class_parents() 這個函數依然返回的是一個數組。如果類對象沒有父類的話,那麼也同樣返回的是一個空的數組。

class TestC {
    use D, E;
}

var_dump(class_uses(new TestC));
// array(2) {
//     ["D"]=>
//     string(1) "D"
//     ["E"]=>
//     string(1) "E"
//   }

最後,我們還可以通過 class_uses() 函數來獲取到當前類對象所使用的 trait 特性信息。

類的哈希及類ID
做過 Java 開發的同學一定都見過所有的類都會有一個 hashCode() 方法。這個方法在 Java 中的作用就是返回一個對象的 Hash 碼值。通常用於對象是否相等以及唯一的判斷,在 Java 中,所有的類都會默認繼承自 Object 這個基類,而這個基類中就自帶這個方法。

但是,在 PHP 中,類是沒有這樣一個全局基類的,自然也就沒有這樣的方法。顯然,只能靠其他的擴展工具幫我們提供這樣的能力了。好巧不巧,SPL 中正好就提供了這樣的功能。

var_dump(spl_object_hash(new TestA));
// string(32) "000000000ed109570000000025e36d74"

$a = new TestA;
var_dump(spl_object_hash($a));
// string(32) "000000000ed109570000000025e36d74"

var_dump(spl_object_id(new TestA));
// int(2)
var_dump(spl_object_id($a));
// int(1)

spl_object_hash() 函數就是用於獲取一個對象的 Hash 值的,它是完整 Hash 值,不像 Java 的 hashCode() 方法返回的是數字類型的值。同樣的類模板所實例化的對象返回的內容是一樣的。

spl_object_id() 返回的是對象的 ID 。它的結果對於不同的 new ,也就是實例化的對象來說是不同的。如果對象一直存在,那麼它的 ID 值是不會發生變化的,而對象被銷燬的話,則 ID 值也會被回收並交給其它對象使用。其實直接打印對象我們就可以看到這個 ID 值。

var_dump($a);
// object(TestA)#1 (0) {
// }
var_dump(new TestA);
// object(TestA)#2 (0) {
// }

井號後面的那個數字就是我們對象的 ID 值,也就是 spl_object_id() 所獲得的內容。

獲取 SPL 庫中的所有可用類信息
這個函數返回的是 SPL 這個庫中所有的可以使用的類名信息。

var_dump(spl_classes());
// array(55) {
//     ["AppendIterator"]=>
//     string(14) "AppendIterator"
//     ["ArrayIterator"]=>
//     string(13) "ArrayIterator"
//     ["ArrayObject"]=>
//     string(11) "ArrayObject"
//     ["BadFunctionCallException"]=>
//     string(24) "BadFunctionCallException"
//     ["BadMethodCallException"]=>
//     string(22) "BadMethodCallException"
//     ["CachingIterator"]=>
//     string(15) "CachingIterator"
//     ["CallbackFilterIterator"]=>
//     string(22) "CallbackFilterIterator"
//     ["DirectoryIterator"]=>
//     string(17) "DirectoryIterator"
//     ["DomainException"]=>
//     string(15) "DomainException"
//     ["EmptyIterator"]=>
//     string(13) "EmptyIterator"
//     ["FilesystemIterator"]=>
//     string(18) "FilesystemIterator"
//     ["FilterIterator"]=>
//     string(14) "FilterIterator"
//     ["GlobIterator"]=>
// …………………………
// …………………………

可以看到,我們前面講過的許多類信息在這裏都可以看到。

迭代器相關函數
迭代器相關的函數在上一篇文章講迭代器的時候其實已經出現過了,那就是非常好用的 iterator_to_array() 這個函數。

$iterator = new ArrayIterator(['a'=>'a1', 'b'=>'b1', 'c'=>'c1']);

var_dump(iterator_to_array($iterator, true));
// array(3) {
//     ["a"]=>
//     string(2) "a1"
//     ["b"]=>
//     string(2) "b1"
//     ["c"]=>
//     string(2) "c1"
//   }

我們可以想象成在這個函數內部,其實就是使用 foreach() 遍歷了一下這個迭代器,並將所有的結果放在數組中返回回來。這個函數還有第二個參數,它的作用是讓鍵不使用原來的鍵值,而是使用默認數組下標的方式排列。

var_dump(iterator_to_array($iterator, false));
// array(3) {
//     [0]=>
//     string(2) "a1"
//     [1]=>
//     string(2) "b1"
//     [2]=>
//     string(2) "c1"
//   }

除了直接獲得迭代器遍歷的結果之外,我們還可以通過一個函數直接獲取迭代器內部元素的數量。

var_dump(iterator_count($iterator)); // int(3)

其實 iterator_count() 這個函數就像是 count() 函數的迭代器版本。

function printCaps($iterator){
    echo strtoupper($iterator->current()), PHP_EOL;
    return true;
}
iterator_apply($iterator, "printCaps", array($iterator));
// A1
// B1
// C1

最後這個 iterator_apply() 函數就是讓我們可以通過一個指定的回調函數來遍歷一個迭代器。

自動加載相關函數
對於自動加載函數來說,我們在最早的文章,也就是講 Composer 的那一系列文章中就已經接觸過了。不過當時我們只是學習了一個 spl_autoload_register() 函數。今天我們就來多學習兩個函數,不過首先還是來看看 spl_autoload_register() 函數的使用。

function autoloadA($class){
    if(is_file('./autoloadA/' . $class . '.php')){
        require_once './autoloadA/' . $class . '.php';
    }
    
}
spl_autoload_register('autoloadA');

spl_autoload_register(function($class){
    if(is_file('./autoloadB/' . $class . '.php')){
        require_once './autoloadB/' . $class . '.php';
    }
});

$sky = new Sky();
$sky->result();
// This is Sky PHP!

$planet = new Planet();
$planet->result();
// This is Planet PHP!

在這段測試代碼中,我們通過回調函數和匿名函數兩種形式註冊了兩個 spl_autoload_register() 。這樣當我們使用當前文件中未定義的類時就會去這兩個 autoload 中查找。在之前講 Composer 時我們就講過,spl_autoload_register() 比 __autolod() 好的地方就是它維護的是一個自動加載列表,相當於是多個 __autoload() 的功能。我們通過另外一個函數就可以看到當前我們已經註冊了多少個自動加載的函數。

var_dump(spl_autoload_functions());
// array(2) {
//     [0]=>
//     string(9) "autoloadA"
//     [1]=>
//     object(Closure)#3 (1) {
//       ["parameter"]=>
//       array(1) {
//         ["$class"]=>
//         string(10) "<required>"
//       }
//     }
//   }

當然,能夠不斷的註冊進來也可以刪除掉。

spl_autoload_unregister('autoloadA');

var_dump(spl_autoload_functions());
// array(1) {
//     [0]=>
//     object(Closure)#3 (1) {
//       ["parameter"]=>
//       array(1) {
//         ["$class"]=>
//         string(10) "<required>"
//       }
//     }
//   }

總結
怎麼樣,一路看下來是不是發現其實不少的功能大家在日常的開發學習中都已經接觸過了。這些函數就是 SPL 擴展庫中所提供的功能了,其實通過這幾篇文章的學習,我們就已經發現了,SPL 擴展庫爲我們提供的都是很基礎的一些 數據結構 、迭代器、設計模式 之類的功能封裝,有很多東西真的比自己實現要簡單方便很多,包括我們下一篇還要繼續學習的文件操作以及設計模式的實現。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章