2012-03-15 21 views
14

Trong khi xem xét một số mã PHP tôi đã phát hiện ra một điều lạ. Dưới đây là ví dụ đơn giản minh họa của nó:Thừa kế PHP, các hàm cha sử dụng các biến con

file A.php:

<?php 
class A{ 
    public function methodA(){ 
     echo $this->B; 
    } 
} 
?> 

file B.php:

<?php 
    class B extends A{ 
     public $B = "It's working!"; 
    } 
?> 

file test.php:

<?php 
    require_once("A.php"); 
    require_once("B.php"); 
    $b = new B(); 
    $b->methodA(); 
?> 

Chạy test.php in ra "Nó hoạt động!", nhưng câu hỏi là tại sao nó hoạt động? :) Đây có phải là một tính năng hoặc một lỗi không? Phương thức methodA trong lớp A cũng có thể gọi các phương thức trong lớp B không nên hoạt động trong OOP.

+1

Một cách để kiểm tra sẽ được tạo ra một lớp "C" mà không xác định B, và xem những gì sẽ xảy ra. Trong khi những gì bạn đã làm sẽ được coi là một thiết kế điên rồ nếu nó không được thực hiện để thử nghiệm, PHP có thể đủ thông minh để làm cho nó hoạt động trong tình huống đó. –

+1

OOP không nói gì về việc liệu các phương thức lớp con có nên hoạt động từ lớp cơ sở hay không. Nó nói rằng các phương thức siêu lớp nên có sẵn cho các lớp con (trừ khi bị ghi đè), nếu có bất cứ điều gì ... nhưng khá im lặng về cách khác xung quanh. Trong thực tế, một số ngôn ngữ OOP thuần khiết nhất trong sự tồn tại thậm chí không quan tâm. – cHao

+0

5+ upvotes? Làm thế nào mà? –

Trả lời

12

Bạn chỉ đang khởi tạo lớp học B. Bỏ qua A cho thời điểm này và giả vờ rằng methodA() là một phần của lớp B.

Khi lớp học B mở rộng A, nó nhận tất cả các chức năng của A. $this->B không được đánh giá cho đến khi mã đang chạy, không phải trước đó. Do đó không có lỗi xảy ra, và sẽ không xảy ra như $this->B tồn tại trong lớp B.

+3

Chỉ hoạt động theo cách đó với biến thành viên công khai. – hakre

6

PHP là ngôn ngữ động. Các phương thức và thành viên dữ liệu được đánh giá trong thời gian chạy. Khi bạn gọi một phương thức hoặc truy cập vào một thành viên, PHP thực sự tìm kiếm một hashtable sắp xếp để tìm hiểu xem phương thức này hoặc thành viên có thể được truy cập trên đối tượng này hay không mà có thể ở bất cứ nơi nào trong hệ thống phân cấp thừa kế. Và không chỉ thừa kế, bạn luôn có thể gán dữ liệu tùy ý cho một đối tượng trên thời gian chạy và mã bên trong lớp sẽ vẫn có thể truy cập nó bằng $ this-> một cái gì đó mà 'cái gì đó' thậm chí không tồn tại trong lớp .

0

Class B kéo dài từ Class A, do đó nó được thừa hưởng phương pháp methodA() từ lớp A.

2

Như PHP là một ngôn ngữ năng động, không có gì sai với kêu gọi các thuộc tính hoặc các phương pháp mà có thể tồn tại trên các trường hợp được sử dụng là nó (trong trường hợp này là một thể hiện của phân lớp B)

1

PHP là một ngôn ngữ động. Khi methodA() được gọi trên một cá thể của B, thành viên B $ B thực sự tồn tại.

$a = new A(); 
$a->methodA(); 

sẽ không hoạt động.

Trong một số ngôn ngữ động, bạn thậm chí có thể xác định các phương thức khi chạy.

1

Điều đó hợp lý với tôi; $ B được tạo sẵn trong đối tượng kết quả nhờ sự xuất hiện của nó trong lớp B. Vì $ this-> B được đánh giá ở thời gian chạy và giá trị được đặt trước đó (khi lớp B được khởi tạo), nó được tìm thấy là đặt đúng. Bạn cũng có thể thực hiện điều này với các phương thức, vì sự tồn tại của chúng không được kiểm tra cho đến khi chúng được thực thi (mặc dù thường là trong trường hợp các phương thức khai báo chúng trừu tượng trong lớp cha, buộc trẻ thực hiện chúng). .

1

Đây là cách OOP được cho là hoạt động.Nó có thể có vẻ hơi lạ lúc đầu, vì bạn nghĩ rằng A sẽ phải biết $this->B là gì trước tiên (và thực sự trong một số ngôn ngữ này sẽ tạo ra cảnh báo trình biên dịch), nhưng hành vi là chính xác vì lớp con bạn đang sử dụng đang xác định biến mà hàm của bạn đang tìm kiếm. Nếu bạn gọi là methodA() từ một phiên bản của A(), thì bạn sẽ gặp lỗi "không xác định".

Bây giờ, những gì sẽ là kỳ lạ (đọc: sai) là nếu NÀY làm việc:

class A { 
    public $b = "Derp"; 
} 
class B extends A { 
    function sayIt() { echo $this->b; } 
} 
$a = new A(); 
$a->sayIt(); 
3

$this chỉ là một biến đối tượng - một người đặc biệt bởi vì đó là một trong hiện tại, nhưng nó vẫn chỉ là một biến đối tượng.

Bởi vì $B::B là biến thành viên công khai, nó có thể được truy cập từ mọi nơi một tham chiếu đến phiên bản B có thể truy cập, ví dụ: với một biến đối tượng.

Vì các thành viên công cộng có thể truy cập ở mọi nơi, mọi chức năng, ngay cả trong vòng A::methodA(), bạn có thể truy cập nó.

Vì vậy, không có nhiều điều để thực sự tự hỏi. Thừa kế lớp trong ví dụ của bạn chỉ liên quan đến việc truyền (vô hình) của biến đối tượng dưới dạng tham số $this "khi yêu cầu A::methodA().

Xem ví dụ sau đó có thể làm cho nó rõ ràng hơn:

function methodA($object) { 
    echo $object->B; 
} 

class B { 
    public $B = "It's working!"; 
    public function methodA() { 
     methodA($this); 
    } 
} 
+0

$ biến này là một thể hiện của lớp B. Trong một ví dụ tương tự biến này trong java cũng là ví dụ B. Trong ví dụ java tôi cần thiết để xác định biến B trong cả hai lớp A và B và khi nói đến in java biến luôn in một từ lớp A. –

+0

Trong PHP bạn cần, nếu ví dụ bạn muốn bảo vệ thành viên, bạn cần định nghĩa nó như được bảo vệ trong A. Khi B mở rộng từ A, mã trong cả hai định nghĩa A và B có thể truy cập nó. Các thành viên được bảo vệ không thể nhìn thấy từ bên ngoài.Các thành viên riêng tư chỉ dành cho định nghĩa hiện tại, vì vậy với một thành viên riêng trong PHP, A không thể truy cập nó nếu nó đã được định nghĩa trong B. – hakre

Các vấn đề liên quan