<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                ## 什么是繼承? 這個繼承詞已經被傳了這么多,我最好的賭注是你已經在某種程度上弄清楚了它的意思。但是,讓我們來看看OOP中繼承的正式定義。繼承是一種允許類繼承另一個類的屬性和方法的機制。繼承另一個類的屬性和方法的類稱為子類,繼承的類稱為父類。 繼承允許我們在現有類的基礎上構建類,允許我們重用代碼并減少我們編寫的代碼量。正如我在本系列之前所指出的,OOP的靈感來自于人類如何思考和與周圍環境互動。繼承也是基于這個模型。我們周圍的很多物體都是其他物體的特殊化。例如,汽車是交通工具的特化,狗是動物的特化,等等,交通工具和動物有這么多,但它們都有一些共同的屬性和方法。單獨定義每個類中的屬性和方法完全是浪費時間。我們可以做的是將所有公共屬性和方法提取到一個單獨的類中,然后創建其他單獨的類來擴展該基類。 ## PHP OOP中的繼承 在PHP OOP中實現繼承非常簡單--使用`extends`關鍵字。我們來看一個例子: ```php class Animal { /** * 構造函數,用于對象初始化 * * @param string $name 設置對象的名稱屬性 * @param int $age 設置對象的年齡屬性 * @param string $color 設置對象的顏色屬性 */ public function __construct( public string $name, public int $age, public string $color ) { } /** * 本函數通過輸出字符串模擬對象進餐的動作,使用的名稱是對象初始化時提供的名稱 * 選擇直接使用echo進行輸出而不是返回值,是因為這里強調的是動作本身而非返回結果 */ public function eat(): void { echo $this->name . " is eating"; } /** * 該方法直接在對象的上下文中使用,用于顯示對象正在睡覺的信息 * 它主要用于演示或調試目的,提供了一種簡單的方法來標識對象狀態 */ public function sleep(): void { echo $this->name . " is sleeping"; } } ``` 這個`Animal`類定義了所有動物通用的屬性和方法。現在,讓我們創建一個繼承自`Animal`類的`Dog`和`Cat`類。 ``` class Dog extends Animal { public function bark() : void { echo $this->name . " is barking"; } } class Cat extends Animal { public function meow() : void { echo $this->name . " is meowing"; } } $dog = new Dog("Rex", 5, "Brown"); $dog->eat(); // Rex is eating $dog->bark(); // Rex is barking $dog->sleep(); // Rex is sleeping $cat = new Cat("Tom", 3, "White"); $cat->eat(); // Tom is eating $cat->meow(); // Tom is meowing $cat->sleep(); // Tom is sleeping ``` Dog和Cat類繼承自Animal類,以及它所附帶的所有內容(屬性和方法)。它們也有自己獨特的屬性和方法。`狗叫()`,貓`叫()`。 從示例中可以清楚地看到,在PHP中,多個類可以從一個類繼承。這就是所謂的*多級繼承*。一個子類也可以有它自己子類,所以我們基本上可以有一個類的家譜。這就是所謂的*分層繼承*。Eg.`Animal`類是`Dog`和`Cat`類的父類,`Dog`類是`GermanShepherd`和`Bulldog`類的父類。 ``` class GermanShepherd extends Dog { public function __construct( public string $name, public int $age, public string $color ) { } public function guard() : void{ echo $this->name . " is guarding"; } } class Bulldog extends Dog { public function __construct( public string $name, public int $age, public string $color ) { } public function guard() : void{ echo $this->name . " is guarding"; } } ``` ## 什么是多態性? 多態性與繼承密切相關。它允許將不同類的對象視為同一類的對象。它允許我們以不同的方式執行一個動作。它允許在不需要知道對象的確切類型的情況下調用方法。多態性是一個希臘詞,意思是“多種形式”。它是OOP的一個強大功能,允許我們編寫靈活和可重用的代碼。 讓我們用一個類比來說明這一點。假設我們有一個`Vehicle`類,它有兩個方法-`drive()`和`startEngine()`。假設我們有三個類-`Car`、`Motorcycle`和`Bicycle`,它們繼承自`Vehicle`類,因此它是方法。 ``` class Vehicle { public function startEngine() : void{ echo "Starting the engine of the vehicle."; } public function move() : void{ echo "Driving a vehicle"; } } class Car extends Vehicle { public function startEngine() : void{ echo "Starting the engine of the car with a key."; } public function move(): void { echo "Driving a car with 4 wheels"; } } class Motorcycle extends Vehicle { public function startEngine() : void { echo "Starting the engine of the motorcycle with a kick."; } public function move() : void { echo "Driving a motorcycle with 2 wheels"; } } class Bicycle extends Vehicle { public function startEngine() : void { echo "Bicycles don't have engines. Just pedal."; } public function move() : void { echo "Driving a bicycle with 2 wheels"; } } $car = new Car(); $car->startEngine(); // Starting the engine of the car with a key. $car->move(); // Driving a car with 4 wheels $motorcycle = new Motorcycle(); $motorcycle->startEngine(); // Starting the engine of the motorcycle with a kick. $motorcycle->move(); // Driving a motorcycle with 2 wheels $bicycle = new Bicycle(); $bicycle->startEngine(); // Bicycles don't have engines. Just pedal. $bicycle->move(); // Driving a bicycle with 2 wheels ``` 現在這里沒有什么新的東西可看。從那以后我們就一直在繼承遺產。現在讓我們看看多態性是如何發揮作用的。 ``` class Player { private Vehicle $vehicle; public function setVehicle(Vehicle $vehicle) { $this->vehicle = $vehicle; } public function drive() { $this->vehicle->startEngine(); $this->vehicle->move(); } } $car = new Car(); $motorcycle = new Motorcycle(); $bicycle = new Bicycle(); $player = new Player(); $player->setVehicle($car); $player->drive(); // Starting the engine of the car with a key. Driving a car with 4 wheels $player->setVehicle($motorcycle); $player->drive(); // Starting the engine of the motorcycle with a kick. Driving a motorcycle with 2 wheels ``` 下面是發生的情況:`Player`類的`$vehicle`屬性和`setVehicle()`方法需要一`個Vehicle`類型。但是,我們能夠傳入`汽車`和`摩托車`對象。當我們調用`$vehicle`的`startEngine()`和`move()`方法時,額外的魔力就來了。`Player`類不需要知道它所處理的對象的確切類型。它只是調用方法,然后調用適當的方法。這就是多態性的作用。 ## 方法覆蓋 使多態性成為可能的一件事是方法重寫。方法重寫是子類重寫其父類的方法的能力。在前面的例子中,`Car`、`Motorcycle`和`Bicycle`類都覆蓋`了Vehicle`類的`startEngine()`和`move()`方法。在某些語言中,默認情況下不會重寫方法。你必須顯式地指定你想要重寫一個方法。在PHP中,方法被默認覆蓋。 另外,有些語言支持方法重載。方法重載是指擁有多個同名但參數不同的方法的能力。PHP不支持方法重載。 這里有一個方法重載的例子,如果我們在PHP中有它的話,它會是什么樣子。 ``` class Vehicle { public function startEngine() { echo "Starting the engine of the vehicle."; } public function move() { echo "Driving a vehicle"; } } class Car extends Vehicle { public function startEngine() { echo "Starting the engine of the car with a key."; } public function startEngine(string $key) { echo "Starting the engine of the car with a $key."; } public function move() { echo "Driving a car with 4 wheels"; } } $car = new Car(); $car->startEngine(); // Starting the engine of the car with a key. $car->startEngine('blue key'); // Starting the engine of the car with a blue key. ``` > 注:上面的代碼會拋出一個錯誤,因為PHP不支持方法重載。這只是癡心妄想! ### 協變和逆變 協變性和逆變性聽起來像是很大的術語,但相信我,它們并不像看起來那么復雜。 協方差是最容易理解的。它允許一個方法的返回類型在子類中是一個比父類中相同方法返回的類型更具體的類型。這是一個很大的問題,讓我們來看看一個例子。 ``` class Vehicle { public static function make(): Vehicle { return new Vehicle(); } } class Car extends Vehicle { public static function make(): Car { return new Car(); } } ``` `Vehicle`類的`make()`方法返回一個`Vehicle`類型。但是在`Car`類中,我們將返回類型專門化為`Car`。這就是協方差的作用。你可以閱讀[Liscov替換原理](https://en.wikipedia.org/wiki/Liskov_substitution_principle)來理解為什么這是可能的。這意味著子類的返回類型不能不具體。 另一方面,矛盾性稍微復雜一點。它使用方法參數而不是返回類型。它允許一個方法的參數類型在子類中是一個比父類中相同參數的類型更不特定的類型。使用我們`的Vehicle`和`Car`類,如果一個方法需要`Vehicle`,自然地,我們可以傳入一`個Car`對象。沒什么新鮮事我們以前見過也做過。但是,如果方法需要一`個Car`對象,我們可以傳入一個`Vehicle`對象嗎?這就是逆變出現的地方。讓我們看一個例子。 ``` class Driver { public function drive(Car $car) { echo "Driving a car"; } } $driver = new Driver(); $driver->drive(new Car()); // Driving a car ``` 現在,如果你試圖傳入一個`Vehicle`對象,你會得到一個錯誤。如果我們有一個從`Driver`繼承的類,那么Contraversion就開始起作用了。 ``` class UberDriver extends Driver { public function drive(Vehicle $vehicle) { echo "Driving a vehicle"; } } $uberDriver = new UberDriver(); $uberDriver->drive(new Vehicle()); // Driving a vehicle ``` 即使父類需要一`個Car`或它的任何子類,我們也可以覆蓋該方法,使其需要一個`Vehicle`對象。這就是作用中的逆變。一開始可能會有點困惑,但你會掌握竅門的。 ### 操作符 在前面的`UberDriver`示例中,如果我們想檢查傳入的對象是否是`Car`對象,該怎么辦?我們不能使用`is_a()`函數,因為它將返回`false`,因為傳入的對象是`Vehicle`對象。這就是`instanceof`操作符的用武之地。它允許我們檢查一個對象是類的實例還是它的子類。所以我們可以這樣做: ``` class UberDriver extends Driver { public function drive(Vehicle $vehicle) { if($vehicle instanceof Car) { echo "Driving a car"; } else { echo "Driving a vehicle"; } } } $uberDriver = new UberDriver(); $uberDriver->drive(new Vehicle()); // Driving a vehicle $uberDriver->drive(new Car()); // Driving a car ``` `instanceof`檢查一個對象是類的實例還是它的子類。它不檢查一個對象是否是父類的實例。所以如果我們做這樣的事情: ``` $car = new Car(); $car instanceof Vehicle; ``` 它應該給我們真實的,但類似于: ``` $vehicle = new Vehicle(); $vehicle instanceof Car; ``` ## 抽象類和方法 讓我們在車輛類比的上下文中反映這一點。在真實的意義上,我們永遠不會有一輛車。我們將有一輛汽車,摩托車,自行車等,所以它沒有意義有一個`車輛`類。這就是**抽象**類和方法概念的由來。 抽象類是不能自己實例化的類(即不能從該類創建對象)。它們是用來繼承的。它們作為其他類的藍圖,類似于常規類,但有一個關鍵的區別:它們可以包含抽象方法,這些方法沒有實現。抽象方法是聲明但未實現的方法。它們應該在孩子的課堂上實施。抽象類也可以包含帶有實現的常規方法。因此,讓我們重構代碼以使用抽象類。 ``` abstract class Vehicle { abstract public function start(): void; abstract public function stop(): void; public function refuel(): void { // Refueling process for vehicles } } class Car extends Vehicle { public function start(): void { echo "Starting the engine of the car with a key."; } public function stop(): void { echo "Stopping the engine of the car."; } } class Motorcycle extends Vehicle { public function start(): void { echo "Starting the engine of the motorcycle with a kick."; } public function stop(): void { echo "Stopping the engine of the motorcycle."; } } class Bicycle extends Vehicle { public function start(): void { echo "Bicycles don't have engines. Just pedal."; } public function stop(): void { echo "Stopping the bicycle."; } } ``` 在這個抽象類中,我們將`start()`和`stop()`定義為抽象方法。這些方法沒有在抽象類中實現,但提供了一個公共接口,任何從`Vehicle`繼承的類都必須實現該接口。從`Vehicle`繼承的具體類必須實現`start()`和`stop()`方法(如果不實現,IDE將拋出錯誤)。`refuel()`方法是一個有實現的常規方法。如果需要的話,它可以在子類中被重寫。 這并不意味著我們不能將`Vehicle`作為返回類型或方法參數。我們仍然可以擁有它。只是不能實例化它。所以我們可以這樣做: ``` class Driver { public function drive(Vehicle $vehicle) { $vehicle->start(); $vehicle->move(); $vehicle->stop(); } } ``` ### 為什么要使用抽象類和方法? 是的,在某種程度上,使類抽象似乎是多余的。為什么不讓他們正常?我們使用抽象類和方法有幾個原因。抽象類和方法允許您創建其他類遵循的藍圖,在代碼庫中強制執行特定結構。`abstract`關鍵字還允許您防止類被實例化,從而保持嚴格、緊密和有組織-沒有機會在這方面出現錯誤。 ## 最終類和方法 說到保持嚴格,`最后`一個關鍵字是另一種方式。`final`關鍵字防止類被繼承,防止方法被重寫。現在有很多關于是否使用`final`關鍵字的爭論。有些人說使用它是一個很好的做法,而另一些人則說不是。我們有一個叫做`unfinalize的`包,用來從包中的類中刪除`final`(實際上它有很多粉絲)。我不想偏袒任何一方。我只告訴你怎么用,然后你自己決定。 ``` final class Car extends Vehicle { public function start(): void { echo "Starting the engine of the car with a key."; } public function stop(): void { echo "Stopping the engine of the car."; } } ``` `汽車`類現在是最后一個類。它不能被繼承。如果你嘗試這樣做,你會得到一個錯誤。方法也是如此。如果你試圖覆蓋一個final方法,你會得到一個錯誤。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看