2011-01-13 47 views
5

Có cách nào để định nghĩa một lớp để nó mở rộng một lớp khác chỉ khi lớp kia có sẵn không?Lớp động mở rộng

+4

Điều này không có ý nghĩa nhiều từ quan điểm kiến ​​trúc - bạn cần mở rộng lớp học hoặc bạn không cần. Bạn đang cố gắng đạt được điều gì? (Có thể có một cách dễ dàng hơn.) –

+4

Không có lý do gì để tự động tạo các lớp, bạn nên có một hệ thống vững chắc không bao giờ nên yêu cầu một thứ như vậy. trừ khi được nêu ở trên, có thể có cách tiếp cận đơn giản hơn cho mục tiêu của bạn. – RobertPitt

+0

RobertPitt chính xác 100%. Tôi sẽ suy nghĩ lại vấn đề bởi vì nó có vẻ như có một lỗi lớn hơn trong cấu trúc cần được xem xét đầu tiên. –

Trả lời

8

Có gì mà sẽ cho phép bạn làm

class Foo extendsIfExist Bar 

Nhưng bạn có thể monkeypatch Foo với runkit 's

Ví dụ từ PHP Manual:

class myParent { 
    function parentFunc() { 
    echo "Parent Function Output\n"; 
    } 
} 

class myChild { 
} 

runkit_class_adopt('myChild','myParent'); 
myChild::parentFunc(); 

Tiện ích mở rộng runkit có sẵn từ PECL. Tuy nhiên, việc sử dụng nó không được khuyến khích vì cần nó hầu như luôn là chỉ báo cho một thiết kế thiếu sót.


Tuyên bố từ chối trách nhiệm: Tôi chỉ giả định một ví dụ như ví dụ sau là lý do bạn đặt câu hỏi. Bỏ qua phần đó của câu trả lời nếu không.

Nếu bạn cần một số chức năng nhất định có điều kiện trong thời gian chạy, hãy xem xét tổng hợp lớp bạn muốn mở rộng, ví dụ: hãy thử điều gì đó dọc theo các dòng của

interface Loggable 
{ 
    public function log($message); 
} 
class Foo implements Loggable 
{ 
    protected $logger; 
    public function setLogger($logger) 
    { 
     $this->logger = $logger; 
    } 
    public function log($message) 
    { 
     if($this->logger !== NULL) { 
      return $this->logger->log($message); 
     } 
    } 
} 

Trong ví dụ trên, chức năng chúng tôi muốn là log(). Vì vậy, thay vì phát hiện nếu một lớp logger có sẵn và sau đó monkeypatching chức năng này vào lớp Foo của chúng tôi, chúng tôi yêu cầu nó yêu cầu chức năng này bằng cách thêm một giao diện Loggable. Nếu tồn tại một lớp Logger, chúng ta khởi tạo và tổng hợp nó trong Foo. Nếu nó không tồn tại, chúng ta vẫn có thể gọi nhật ký nhưng nó sẽ không làm gì cả. Đây là nhiều hơn nữa solid.

+0

Giải pháp để cung cấp "mở rộng nếu tồn tại" mà không sử dụng eval: http://stackoverflow.com/a/9898049/441739 –

1

Ý của bạn là gì?

<?php 

class Foo{ 
} 

if(class_exists('Foo')){ 
    class SubFoo extends Foo{ 
    } 
} 

if(class_exists('Bar')){ 
    class SubBar extends Bar{ 
    } 
} 

$a = new SubFoo; // OK 
$b = new SubBar; // Fatal error: Class 'SubBar' not found 
+0

Không hay, nhưng tốt hơn so với phương pháp 'eval()'! –

2

Đây là câu trả lời và phần mở rộng cho câu trả lời của Pekka.

Thứ nhất tại Pekka, tôi nghĩ rằng các eval là hoàn toàn sai, những gì là sai với

if(class_exists("bar")) 
{ 
    class foo extends bar 
    { 

    } 
} 

đó cũng là câu trả lời là tốt của tôi.

2

gặp một yêu cầu tương tự gần đây, nơi một lớp trong thư viện của tôi cần để tự động mở rộng từ ClassB (nếu có), nếu không mở rộng từ lớp A.

Giải pháp của tôi (mã của tôi là namespaced, cùng khái niệm áp dụng không phân biệt) :

namespace someNamespace; 

spl_autoload_register(function($class) { 
    if (strcasecmp($class, 'someNamespace\SomeFakeClass') === 0) { 
     if (class_exists('ClassB',false)) { 
      class_alias('ClassB', 'someNamespace\SomeFakeClass'); 
     } else { 
      class_alias('ClassA', 'someNamespace\SomeFakeClass'); 
     } 
    } 
}, true, true); 

/** @noinspection PhpUndefinedClassInspection */ 
/** @noinspection PhpUndefinedNamespaceInspection */ 
class MyClass extends \someNamespace\SomeFakeClass { 
    # ... real logic here ... 
} 

Sử dụng giải pháp trên, lớp MyClass sẽ tự động kế thừa từ ClassB nếu tồn tại, nếu không nó được thừa hưởng từ ClassA.

Giải pháp này tránh sử dụng eval, đây là một lợi thế lớn đối với tôi.

Hy vọng điều này sẽ hữu ích.

CHỈNH SỬA: Chỉ cần lưu ý, ký hiệu @noinspection tồn tại để các IDE chẳng hạn như PHPStorm sẽ không báo cáo lỗi liên quan đến lớp không tồn tại.

4

Tôi đã thực hiện theo cách này.

if (class_exists('parentClass') { 
    class _myClass extends parentClass {} 
} else { 
    class _myClass {} 
} 
class myClass extends _myClass 
{ 
... 
} 
+0

Lỗi nếu tệp ở bên ngoài 'Lỗi nghiêm trọng: Khai báo lớp có thể không được lồng nhau' –