PHP 介面實際上如何改變類別的行為
P粉289775043
P粉289775043 2023-09-02 23:49:28
0
1
481

根據 PHP 文檔,

物件介面可讓您建立指定類別必須實作哪些方法的程式碼,而無需定義這些方法的實作方式。

因此,介面就像一個具有預先定義方法的類,仍然需要使用 -> 符號來存取

但是,ArrayAccess 介面提供對物件作為陣列的存取。可以使用 $object->property$object["property"]

存取對象

我無法理解 ArrayAccess 如何讓更改物件語法成為可能。我寫了一段程式碼來嘗試複製 ArrayAccess 方法只有一個的效果,但它拋出錯誤

// Using the PHP ArrayAccess Interface namespace A { class myclass implements \ArrayAccess { public function offsetExists($offset) { return true; } public function offsetGet($offset) { // changed behaviour return $this->{$offset} ?? null; } public function offsetSet($offset, $value) {} public function offsetUnset($offset) {} } $myclass = new myclass(); $myclass->access = 'Interface'; echo $myclass['access']; // "Interface" }; //Trying to implement my own ArrayAccess Interface namespace B { interface MyArrayAccess { public function offsetGet($offset); } class myclass implements MyArrayAccess { public function offsetGet($offset) { // change behaviour return $this->{$offset} ?? null; } } $myclass = new myclass(); $myclass->access = 'Interface'; echo $myclass['access']; // Fatal error: Uncaught Error: Cannot use object of type B\myclass as array } 

請幫我正確解釋。謝謝

P粉289775043
P粉289775043

全部回覆 (1)
P粉702946921

我並不是說介面“改變了類別的行為”,而是說介面使擴充類別功能變得容易。

要理解接口,作為一個物件導向的程式設計概念,我們首先應該理解它要解決什麼問題。

「Interface」旨在解決什麼問題?

介面是一種契約。這是在 PHP 中實作duck-typing的方法。您需要從庫編寫者的角度思考,他希望向其他人公開功能。例如,

class Greeter { public function greet($person) { echo "Hello, {$person->getName()}!\n"; } }

為了確保函式庫使用者知道$person需要有getName()方法,您可以建立一個類別Person> 有一個getName()方法。然後使用類型宣告來偵測程式碼執行時的潛在錯誤已解析。

class Greeter { public function greet(Person $person) { echo "Hello, {$person->getName()}!\n"; } } class Person { public string $name; public function getName(): string { return $this->name; } }

假設有另一個庫可以用食物來餵養東西:

class Feeder { public function feed(Eater $eater, string $food) { $eater->eat($food); } } class Animal { private $stomach = []; public function eat(string $food) { $stomach = $food; } }

考慮這個...

現在,假設使用者想要寫一個既可以吃飯又可以打招呼的Pet類別。使用者不想只是為了Pet再次編寫這些功能。

如何寫Pet以便同時使用GreeterFeeder函式庫?

也許是這樣的?

class Pet extends Person, Animal { }

不幸的是,PHP不支援多重繼承。一個類別只能擴充一個類別。上面的程式碼無效。所以在目前的情況下,使用者只能使用其中一個函式庫。

此外,對於不同的事物,「名稱」可能是一個非常不同的概念(例如,一個人可能會使用getName() 返回$first_name$last_name代码>)。您的函式庫類別中可能沒有合理的預設實作getName()方法。

所以,身為一個函式庫編寫者,您希望他/她的函式庫對使用者盡可能靈活。你能做什麼?

如何用 PHP 中的「介面」解決這個問題?

介面是方法簽章的宣告。這是在沒有特定類別/繼承要求的情況下聲明庫要求的捷徑。

使用接口,您可以像這樣重寫兩個函式庫:

Greeter函式庫

class Greeter { public function greet(Namer $namer) { echo "Hello, {$namer->getName()}!\n"; } } interface Namer { public function getName(): string; }

Feeder

class Feeder { public function feed(Eater $eater, string $food) { $eater->eat($food); } } interface Eater { public function eat(string $food); }

不需要一個特定的類別(或父類別繼承),一個類別可以實作多個介面。所以下面的Pet類別在 PHP 中是完全有效的:

class Pet implements Namer, Eater { private array $stomach = []; private string $name = ''; public function __construct(string $name) { $this->name = $name; } /** * Implements Namer. */ public function getName(): string { return $this->name; } /** * Implements Eater. */ public function eat(string $food) { $this->stomach[] = $food; } } $greeter = new Greeter(); $feeder = new Feeder(); $pet = new Pet('Paul'); $greeter->greet($pet); $feeder->feed($pet, 'a biscuit');

現在,此Pet類別的物件可以與Greeter函式庫和Feeder函式庫一起使用。

ArrayAccess介面怎麼樣?

ArrayAccess介面不是由第三方宣告的介面庫編寫者,而是由核心 PHP 編寫者編寫。核心PHP編寫器對此提供了更深刻的支援。

有點像是我們之前提到的接口,PHP 為實作它的類別提供功能。但核心 PHP 不是提供上面的GreeterFeeder範例,而是提供實作 ArrayAccess 的類別的語法糖。這表示您可以使用更簡潔的程式碼來處理實作 AccessAccess 介面的類別。

在官方範例中,

container = array( "one" => 1, "two" => 2, "three" => 3, ); } public function offsetSet($offset, $value) { if (is_null($offset)) { $this->container[] = $value; } else { $this->container[$offset] = $value; } } public function offsetExists($offset) { return isset($this->container[$offset]); } public function offsetUnset($offset) { unset($this->container[$offset]); } public function offsetGet($offset) { return isset($this->container[$offset]) ? $this->container[$offset] : null; } }

如果您實現了它們,則代替這些:

$obj = new Obj; $obj->offsetSet(10, "hello"); $obj->offsetSet(11, "world"); if ($obj->offsetUnset(12)) { $obj->offsetUnset(12); } echo $obj->offsetGet(11);

您可以將$obj與類似陣列的語法一起使用,以使程式碼更短:

$obj = new Obj; $obj[10] = "hello"; $obj[11] = "world"; if (isset($obj[12])) { unset($obj[12]); } echo $obj[11];
    最新下載
    更多>
    網站特效
    網站源碼
    網站素材
    前端模板
    關於我們 免責聲明 Sitemap
    PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!