2014-12-30 252 views
1

我是一個noob,當涉及到面向對象時,請隨身攜帶,因爲我不確定我使用的是正確的術語,但我會盡我所能。在子類中訪問私有變量

我有一堂課。

<?php 

class WC_Swatch_Picker { 

private $size; 
private $attributes; 
private $selected_attributes; 
private $swatch_type_options; 

public function __construct($product_id, $attributes, $selected_attributes) { 
    $this->swatch_type_options = maybe_unserialize(get_post_meta($product_id, '_swatch_type_options', true)); 

    if (!$this->swatch_type_options) { 
     $this->swatch_type_options = array(); 
    } 

    $product_configured_size = get_post_meta($product_id, '_swatch_size', true); 
    if (!$product_configured_size) { 
     $this->size = 'swatches_image_size'; 
    } else { 
     $this->size = $product_configured_size; 
    } 

    $this->attributes = $attributes; 
    $this->selected_attributes = $selected_attributes; 
} 

public function picker() { 
    ?> 

    <table class="variations-table" cellspacing="0"> 
     <tbody> 
      <?php 
      $loop = 0; 
      foreach ($this->attributes as $name => $options) : $loop++; 
       $st_name = sanitize_title($name); 
       $hashed_name = md5($st_name); 
       $lookup_name = ''; 
       if (isset($this->swatch_type_options[$hashed_name])) { 
        $lookup_name = $hashed_name; 
       } elseif (isset($this->swatch_type_options[$st_name])) { 
        $lookup_name = $st_name; 
       } 
       ?> 
       <tr> 
        <td class="label"><label for="<?php echo $st_name; ?>"><?php echo WC_Swatches_Compatibility::wc_attribute_label($name); ?></label></td> 
        <td> 
         <?php 
         if (isset($this->swatch_type_options[$lookup_name])) { 
          $picker_type = $this->swatch_type_options[$lookup_name]['type']; 
          if ($picker_type == 'default') { 
           $this->render_default($st_name, $options); 
          } else { 
           $this->render_picker($st_name, $options, $name); 
          } 
         } else { 
          $this->render_default($st_name, $options); 
         } 
         ?> 
        </td> 
       </tr> 
      <?php endforeach; ?> 
     </tbody> 
    </table> 
    <?php 
} 

我試圖延長該類這樣我可以輸出picker()方法顯示<table>作爲<div>代替。

這是我試圖擴展這個類。

class SSi_WC_Swatch_Picker extends WC_Swatch_Picker { 

public function picker() { 
    ?> 

    <div class="variations-table"> 

      <?php 

      $loop = 0; 
      foreach ($this->attributes as $name => $options) : $loop++; 
       $st_name = sanitize_title($name); 
       $hashed_name = md5($st_name); 
       $lookup_name = ''; 
       if (isset($this->swatch_type_options[$hashed_name])) { 
        $lookup_name = $hashed_name; 
       } elseif (isset($this->swatch_type_options[$st_name])) { 
        $lookup_name = $st_name; 
       } 
       ?> 
       <div> 
        <div class="label"><label for="<?php echo $st_name; ?>"><?php echo WC_Swatches_Compatibility::wc_attribute_label($name); ?></label></div> 
        <div> 
         <?php 
         if (isset($this->swatch_type_options[$lookup_name])) { 
          $picker_type = $this->swatch_type_options[$lookup_name]['type']; 
          if ($picker_type == 'default') { 
           $this->render_default($st_name, $options); 
          } else { 
           $this->render_picker($st_name, $options, $name); 
          } 
         } else { 
          $this->render_default($st_name, $options); 
         } 
         ?> 
        </div> 
       </div> 
      <?php endforeach; 

      ?> 

    </div> 

    <?php 
} 

} 

我在屏幕上顯示出一個<div>像我想,但我得到: Notice: Undefined property: SSi_WC_Swatch_Picker::$attributesWarning: Invalid argument supplied for foreach()

我認爲,這是因爲父類定義$attributes作爲private

不幸的是我不能改變父類。

所以我的noob問題是$attributes可以以某種方式從子類訪問嗎?我沒有在父類中看到__get或__set方法,所以我猜測沒有。


UPDATE

的顯影劑改變private屬性protected。所以這將解決我訪問屬性的問題。

再次感謝社區提供備用解決方案。

+2

你沒有獲得父母的私有變量(這就是爲什麼它們被稱爲私有的),你可以雖然 –

+2

是的,你需要修改構造函數,然後跟蹤一組單獨的成員變量中的所有內容。儘管在那時你可能會創建一個全新的類,除非你需要遵守與另一個接口的契約(即某事需要WC_Swatch_Picker的一個實例)。另外'picker'方法很醜陋。你不應該像在課堂上那樣切換進出PHP。我知道這是一個WP/WooCommerce的東西,但我只是把它扔到那裏,讓你從來沒有**自己做,當你有選擇:-) – prodigitalson

+1

如果它是你自己的類,你可以使用'protected'而不是'private'。然後你的子類可以訪問父類變量。這種違反封裝,但這是你可以做的事情。 – Gohn67

回答

1

您可以使用反射:

// setup a reflector for WC_Swatch_Picker::size property 
$ref = new ReflectionProperty("WC_Swatch_Picker", "size"); 
$ref->setAccessible(true); 

// read the private "size" property 
$size = $ref->getValue($this); 

// update the private "size" property 
$ref->setValue($this, $size); 

注:這是有點低效率的,所以如果你打算這樣做了很多,你應該繼續根據需要可重複使用的ReflectionProperty實例的副本。

+0

感謝您的建議,我將不得不更多地關注它,因爲它完全脫離了我的駕駛室。我假設我會根據4個私有屬性創建2個反射?你的建議會進入我的擴展類中,但在'picker()'方法之前嗎? – Ken

+0

我想你可能會設置4個反射,每個屬性一個。而且你可能會在擴展類的構造函數中這麼做,這樣你就不會重新創建反射對象。我也只是告誡說,這種方法是醜陋的,只有在不能將基類從私有變爲受保護的情況下才能使用。 –

1

另一種可能性是重寫構造你的子類,並設置自己的屬性$attributes

class SSi_WC_Swatch_Picker extends WC_Swatch_Picker { 

    private $attributes; 

    public function __construct($product_id, $attributes, $selected_attributes) { 
     $this->attributes = $attributes; 

     // Call the parent constructor. 
     parent::__construct($product_id, $attributes, $selected_attributes); 
    } 

    // ... 
} 
+0

這可能會導致問題,因爲會有兩個$屬性屬性,一個是基類中的私有屬性,另一個是子類中的私有屬性。不同的方法會得到不同的數據。您可以通過使用pass byref(&$ attributes)來解決該問題,但我不確定。 –

+0

你是對的,但沒有乾淨的方式來做到這一點。你的解決方案很好,但剎車的財產的可訪問性。沒有修改父類,我看不到一個好辦法做到這一點。 – Gnucki