2012-05-22 125 views
4

如果我有一個擴展類Bar和Bar實例的Foo類,那麼無論如何要使用該Bar實例來「填充」一個Foo的新實例?基本上,我只能檢索Bar,但我想在我的代碼中使用Foo,因爲它給了我很多其他方法。在PHP中,從基類實例創建擴展類的對象

我看到不少解決方案都出現類似的問題,但它們都似乎是python或c#。

我無法使用ReflectionClass :: newInstanceArgs,因爲我不能訪問進入Bar構造函數的數據以便首先創建它。

+0

你可能會寫一個Foo的函數/構造函數,它帶了一個Bar實例並填充了Foo實例 – gunnx

+0

你爲什麼要這樣做?這聽起來像是有陰險的事情.. –

+0

我不認爲你可以在PHP中投射自定義對象。也許你可能會在[這篇文章](http://stackoverflow.com/a/2232065/1028949)中找到一些有用的信息。 – Quantastical

回答

1

有沒有內置的方法可以輕鬆地做你想做的。這些類的接口必須重新設計一點。也許是這樣的:

<?php 
class Bar 
{ 
    ... 
} 

class Foo extends Bar 
{ 
    public static function fromBar(Bar $bar) 
    { 
     $foo = new self(); 
     ... (copy data here) ... 

     return $foo; 
    } 
} 

+0

謝謝。是的,意識到根據我的問題期望能夠做到這是不合理的,我想我會按照這些方式做一些事情。可能會放棄'擴展',並將Bar作爲Foo的一個屬性。 – petesiss

2

推薦的方法是通過dependency injection。您的Foo的構造函數可以接受Bar的實例,然後您必須編寫代碼以加載Bar對象中新對象Foo的狀態。

如果PHP具有完全符合您所描述的功能,則會出現問題,因爲即使Foo擴展了Bar,這兩個類仍然可能會有很大的不同。我沒有看到PHP如何聰明地知道如何自動將一個類的實例轉換爲另一個類的實例。這樣說,在正確的情況下,下面的(非常冒險的)「解決方案」可以做你所描述的。我不會推薦實際使用它。我主要只是想表明,你不得不訴諸一些奇怪的東西來做到這一點。

function convertObject($object, $newClass) 
{ 
    return unserialize(
     preg_replace(
      '/^O\:\d+\:"[^"]+"/', 
      'O:'.strlen($newClass).':"'.$newClass.'"', 
      serialize($object) 
     ) 
    ); 
} 
+0

是的...我不會那樣做convertObject。我想在這種情況下,考慮到我們的目的是爲擴展對象提供一個合適的初始狀態,基類的屬性似乎並不是那麼神奇......但當然並非總是如此。我想我會去讓Bar成爲Foo的一個財產。 – petesiss

0

我剛寫的東西這個例子中,用於擴展可能需要對上述核心驅動程序文件的附加支持包(S)定製驅動程序基礎上的。

// File: parent.php 

class parent_class() { 

    protected $_protected_object; // set in constructor 
    protected $_protected_var = "Something dynamic"; 

    public function __construct() { 
     // keep in mind that if you don't override this constructor, this will execute when extended 
    } 

    public function create_resource() { 
     $this->_protected_object = new SomeObjectInstance(); 
    } 

    public function child_class() { 

     static $child = null; 

     if (is_null($child)) { 

      $file = "child.php"; 

      if (!\file_exists($file)) { 
       throw new Exception("Couldn't load '$file', doesn't exist"); 
      } else { 

       require_once($file); 

       $child = new child_class(); 
       $child->__overload("_protected_object", $this->_protected_object)->__overload("_protected_var", $this->_protected_var); 

      } 

     } 

     return $child; 

    } 

} 

// File: child.php 

class child_class extends parent_class { 

    protected function __overload($index, &$value) { 

     $this->$index =& $value; 
     return $this; 

    } 

    public function __construct() { 
     // REMEMBER: if you don't declare this method, the parent's constructor will execute 
    } 

    public function extended_func() { 
     // code 
    } 

    public function etc() { 
     // code 
    } 

} 

// Code instantiating objects: 

$parent = new parent_class(); 
$parent->create_resource(); 

var_dump($parent); 

/** 
* Would output something like this: 
* 
* object(parent_class)#1 (2) { 
* ["_protected_object":protected]=> 
* object(SomeObjectInstance)#2 (*) { 
*  %OBJECT PROPERTIES% 
* } 
* ["_protected_var":protected]=> 
* string(17) "Something dynamic" 
* } 
*/ 

$child = $parent->child_class(); 

var_dump($child); 

/** 
* Would output something like this: 
* 
* object(child_class)#3 (2) { 
* ["_protected_object":protected]=> 
* &object(SomeObjectInstance)#2 (*) { 
*  %OBJECT PROPERTIES% 
* } 
* ["_protected_var":protected]=> 
* &string(17) "Something dynamic" 
* } 
*/ 

注意,第二的var_dump()爲$子輸出相同的信息$父,但你可以看到現在說屬性的前面有符號(&),表示現在有引用。因此,如果您在父類實例中更改了有關這兩個屬性的任何內容,它將反映在子類實例中。