2014-12-30 242 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