2011-12-10 70 views
2

我已經把自己陷入了PHP的境地,我需要訪問一個類的構造函數而不知道類是什麼。我可能會從錯誤的設計角度來解決這個問題,所以就是這種情況 - 我在Drupal工作,在他們的無類別數據處理上寫了一個輕微的OO層,以允許一些非Drupal開發人員加入我的項目。在PHP中,是否有可能返回一個類的構造函數?

在Drupal中,所有內容都被視爲一個節點。所以,我做了一個抽象類 - 節點。任何內容都必須具有特定的內容類型。使用OO,這很容易 - 我製作一個擴展Node的Person類,或一個擴展Node的Event類等。現在出現了棘手的部分 - 我的項目的一部分允許這些節點「包含」在其他節點中。也就是說,如果節點A包含節點B,則無論何時顯示A,都會顯示來自B的數據。這意味着每當節點A被實例化時,它也需要實例化節點B.但是... Node是一個抽象類。所以,我不能實例化一個原始節點。我必須實例化其實現類之一。所以,據我所知,我需要編寫一個抽象的靜態函數,所有的擴展類必須實現返回構造函數......或者,我需要以某種方式使用反射來確定類型,並以某種方式調用適當的類構造函數?

不考慮Drupal,從PHP/OO編程的角度來看,處理這個問題最合適的方法是什麼?

這裏是我的代碼:

<?php 

abstract class Node { 

    public $title, $short_summary, $full_summary, $body, $uri, $machine_type_name, $included_content; 

    public function __construct($node) { 

     ## 
     ## Set simple values 
     $this->title = $node->title; 
     $this->body = $node->body['und'][0]['safe_value']; 

     ## 
     ## Set clean uri if aliased 
     if (drupal_lookup_path('alias', 'node/'.$node->nid)) { 
      $this->uri = '/'.drupal_lookup_path('alias', 'node/'.$node->nid); 
     } else { 
      $this->uri = '/node/'.$node->nid; 
     } 

     ## 
     ## Set short summary if exists, else short form of body text 
     if(strlen($node->body['und'][0]['safe_summary'])) { 
      $this->short_summary = $node->body['und'][0]['safe_summary']; 
     } else { 
      $this->short_summary = text_summary($node->body['und'][0]['safe_value'], NULL, 100); 
     } 

     ## 
     ## Set full summary to concatenation of body 
     $this->full_summary = text_summary($node->body['und'][0]['safe_value'], NULL, 600); 

     ## 
     ## Add included content if module is enabled 
     if (module_exists('content_inclusion')) { 
      // is this possible? Is there a better design pattern available? 
      $this->included_content = Node::get_constructor(node_load($node->content_inclusion['und'][0]['value'])); 
     } 

    } 

    public static abstract function get_all_published(); 
    public static abstract function get_by_nid($nid); 
    public static abstract function get_constructor(); 
} 

?> 
+0

瑞恩,滿足['static'](http://php.net/lsb)。我相信你會成爲好朋友。 – salathe

+0

雖然我很感謝您的幫助,但我清楚地瞭解了我上面代碼中的static關鍵字。除非我錯過了一些東西,否則我不明白這是如何解決我的問題。 – rybosome

+1

但是你有沒有遇到過它相同的雙胞胎'靜態',用於*晚期靜態綁定*? ([docs](http://php.net/lsb)) – salathe

回答

2

你的意思是這樣:?

class MySubClass extends Node 
{ 
    public static function get_constructor() 
    { 
     return new self(); 
    } 
} 

// ... 

$object = MySubClass::get_constructor(); 

或者,如果你有PHP 5.3,你可以使用late static binding與您可以使用return new static();$class = get_called_class(); return new $class();。等

完整例如:

abstract class Node 
{ 
    public $test; 

    public function __construct() 
    { 
     $this->test = 'Node'; 
    } 

    public static function get_constructor() 
    { 
     return new static(); 
    } 
} 

class MySubClass extends Node 
{ 
    public function __construct() 
    { 
     $this->test = __CLASS__ . PHP_EOL; 
    } 
} 

// ... 

$object = MySubClass::get_constructor(); 
echo $object->test; // echoes "MySubClass" 
+0

雖然Node是一個抽象類,所以它不能被實例化。我需要一個實現Node的未知類來實例化。 – rybosome

+0

它應該仍然工作。只要你用你的子類名稱來調用它。 (例如'MySubClass :: get_constructor();') –

+0

http://codepad.org/cNyMNob4 –

相關問題