Php 访问子类中的私有变量

Php 访问子类中的私有变量,php,class,oop,subclass,Php,Class,Oop,Subclass,我有课 <?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

我有课

<?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
}
我在屏幕上的输出显示了我想要的
,但我得到了:
注意:未定义的属性:SSi_WC_样例_选择器::$attributes
警告:为foreach()提供的参数无效。

我认为这是因为父类将
$attributes
定义为
private

不幸的是,我无法更改父类

所以我的noob问题是,
$attributes
是否可以通过某种方式从子类访问?我在父类中没有看到uuuu get或uuuu set方法,所以我猜没有


开发人员正在将
private
属性更改为
protected
。这将解决我访问属性的问题

您可以使用反射:

// 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实例的副本,以便根据需要重用。

另一种可能是重写子类中的构造函数,并设置自己的属性
$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 );
    }

    // ...
}

您无法访问父级的私有变量(这就是为什么它们被称为私有变量),您可以将属性保存到构造函数中的变量中,但您需要修改构造函数,然后在一组单独的成员变量中跟踪所有内容。尽管在这一点上,您也可以创建一个全新的类,除非您需要遵守与另一个接口的契约(即,某些东西需要WC_Swatch_Picker的实例)。而且,
picker
方法很难看。你不应该像在类中那样进出PHP。我知道这是一个WP/WooCommerce的东西,但我只是把它扔出去,这样当你有选择的时候,你就永远不会自己做:-)如果它是你自己的类,你可以使用
protected
而不是
private
。然后您的子类可以访问父类变量。这种做法违反了封装,但您可以这样做。@Gohn67同意,但不幸的是,它不是我的类,因此无法更改父类。我确实打电话给开发人员,想看看他是否会改为
受保护的
,但我没有收到回音,所以我试图找到替代的解决方法。@Ken也许你可以复制类并替换picker方法。那么就不需要子类了。我不认为这是一个大问题,在这种情况下。谢谢你的建议,我将不得不进一步研究,因为它完全超出了我的驾驶室。我假设我将根据4个私有属性创建2个反射?你的建议会在我的扩展类中,但在
picker()
方法之前吗?我想你可能会设置4个反射,每个属性一个反射。我认为,您可能会在扩展类的构造函数中这样做;这样,您就不会继续重新创建反射对象。我还要提醒的是,这种方法很难看,只有在无法将基类从private更改为protected时才应该使用。这可能会导致问题,因为将有两个$attributes属性,基类中有一个private,子类中有一个private。不同的方法会得到不同的数据。您可以通过使用passbyref(&$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 );
    }

    // ...
}