【问题标题】:$this->value losing, well, its value$this->value 失去了,好吧,它的价值
【发布时间】:2012-11-06 04:20:16
【问题描述】:

我正在使用的 PHP 文件有问题,我似乎找不到解决方案。

在代码的一部分中设置了$this->value 的值,并且根据我的测试,该值设置正确。

但是,稍后在同一代码中$this->value 为空。

代码如下:

<?php

class Padd_Input_Advertisement {

    protected $keyword;
    protected $value;
    protected $name;
    protected $description;

    function __construct($keyword,$name,$description='') {
        $this->keyword = $keyword;
        $this->value = unserialize(get_option($keyword));
        $this->name = $name;
        $this->description = $description;
    }

    public function get_keyword() {
        return $this->keyword;
    }

    public function set_keyword($keyword) {
        $this->keyword = $keyword;
    }

    public function get_value() {
        return $this->value;
    }

    public function set_value($value) {
        $this->value = $value;
    }

    public function get_name() {
        return $this->name;
    }

    public function set_name($name) {
        $this->name = $name;
    }

    public function get_description() {
        return $this->description;
    }

    public function set_description($description) {
        $this->description = $description;
    }

    public function  __toString() {

        $strHTML  = '';
        $strHTML .= '<tr valign="top">';
        $strHTML .= '   <th scope="row"><label for="' . $this->keyword . '">' . $this->name . '</label></th>';
        $strHTML .= '   <td>';
        $strHTML .= '       <label for="' . $this->keyword. '_alt_desc">Short Description</label><br />';
        $strHTML .= '       <input name="' . $this->keyword . '_alt_desc" type="text" id="' . $this->keyword . '_alt_desc" value="' . $this->value->get_alt_desc() . '" size="80" /><br />';
        $strHTML .= '       <label for="' . $this->keyword. '_img_url">Image URL</label><br />';
        $strHTML .= '       <input name="' . $this->keyword . '_img_url" type="text" id="' . $this->keyword . '_img_url" value="' . $this->value->get_img_url() . '" size="80" /><br />';
        $strHTML .= '       <label for="' . $this->keyword. '_web_url">Website</label><br />';
        $strHTML .= '       <input name="' . $this->keyword . '_web_url" type="text" id="' . $this->keyword . '_web_url" value="' . $this->value->get_web_url() . '" size="80" />';
        $strHTML .= '       <br /><small>' . $this->description . '</small>';
        $strHTML .= '   </td>';
        $strHTML .= '</tr>';
        return $strHTML;
    }

}

?>

function __construct 的顶部,设置了值,我确认会发生这种情况。

但是,在底部函数function __toString中,$this-&gt;value是空白的。

知道是什么原因造成的吗?

编辑

因此,回顾一下,$this->value 在 __construct 函数中设置正确,但在 __toString 函数中为空白。

编辑 2

我还应该提到,在 __construct 函数中设置的其他变量在 __toString 函数中起作用,例如 $this->keyword。只是 $this->value 变为空白。

编辑 3 类是这样调用的

$padd_options['advertisements'] = array(
    new Padd_Input_Advertisement(
        PADD_NAME_SPACE . '_ads_125125_1',
        'Square Ad 1 (125x125)',
        'The advertisement will be posted at the side bar.'
    ),
    new Padd_Input_Advertisement(
        PADD_NAME_SPACE . '_ads_125125_2',
        'Square Ad 2 (125x125)',
        'The advertisement will be posted at the side bar.'
    ),
    new Padd_Input_Advertisement(
        PADD_NAME_SPACE . '_ads_125125_3',
        'Square Ad 3 (125x125)',
        'The advertisement will be posted at the side bar.'
    ),
    new Padd_Input_Advertisement(
        PADD_NAME_SPACE . '_ads_125125_4',
        'Square Ad 4 (125x125)',
        'The advertisement will be posted at the side bar.'
    ),
);

【问题讨论】:

  • __toString() 是 php 中的一种神奇方法,您可以将其更改为其他名称并尝试吗?
  • 空白怎么办? var_dump__toString 里面说什么?
  • get_option() 在哪里定义?获取Call to undefined function get_option()
  • 您是否尝试过将 $value 的数据类型从受保护更改为私有或公共?
  • 大家好。只是为了消除混乱。我怀疑这是一个基于 Wordpress 的项目,get_option() 是在 core.xml 中定义的。仅供参考:codex.wordpress.org/Function_Reference/get_option

标签: php variables


【解决方案1】:

这是因为未序列化的对象如果不知道类的类型,保留方法。

当您反序列化get_keyword() 函数调用的结果时,如果序列化对象的类未知,PHP 将回退到特殊类__PHP_Incomplete_Class_Name。这个类基本上是一个虚拟类:它没有任何方法。但是,它允许您访问反序列化对象的属性。

因此,如果您希望能够调用 $this-&gt;value 的方法(这就是您在 __toString 中所做的),则必须在调用 unserialize 之前包含声明 $this-&gt;value 类型的文件.

[编辑]您可以查看the PHP manual 了解有关反序列化过程的更多详细信息。

【讨论】:

  • var_dump($this-&gt;value);__toString 方法中的输出是什么?如果我是对的,您应该会看到类似object(stdClass)#2 (1) { ... } 的内容。如果是这种情况,您所要做的就是包含声明未序列化对象的实际类型的文件。
  • "Blank" 可能意味着很多东西......你的意思是 NULL 吗? var_dump 函数是一种检查对象以了解其类型的标准方法。
  • 不,它们的创建方式与$this-&gt;value 不同。后者是使用unserialize 方法创建的,这是一个很大的区别。
  • 可能发生的情况是来自 unserialize 的 StdClass 通过引用返回并限定在构造函数中。当函数到期时,对象被销毁并且引用被清除。这可能就是下面的修复有效的原因。将对象重新分配给另一个变量会强制引用保持不变。
  • 注意 unserialize 为反序列化时未找到的类返回一个 __PHP_Incomplete_Class_Name 实例(不是stdClass,也不是StdClass
【解决方案2】:

这就是给你带来问题的原因:

$this->value = unserialize(get_option($keyword));

正如其他人之前指出的那样,您可以使用get_option() 函数的实际声明和包装get_alt_desc(), get_img_url(), get_web_url() 方法的类来更新您的原始帖子。

可以假设get_option()函数返回一个序列化对象,该对象实现了以下public方法:

public function get_alt_desc() { /* custom code */ }
public function get_img_url() { /* custom code */ }
public function get_web_url() { /* custom code */ }

通过序列化和反序列化您的对象,您将无法访问上述所有方法。 为避免这种情况,您需要修改 get_option() 函数以返回实际对象,而不是它的序列化表示。

假设有一个代表您的对象的Value 类:

class Value {
    protected $alt_desc;
    protected $img_url;
    protected $web_url;

    public function __construct($keyword) {
        $this->alt_desc = $keyword[0]; // some string build around $keyword
        $this->img_url = $keyword[1]; // some string build around $keyword 
        $this->web_url = $keyword[2]; // some string build around $keyword
    }

    public function get_alt_desc() {
        return $this->alt_desc;
    }

    public function get_img_url() {
        return $this->img_url;
    } 

    public function get_web_url() {
        return $this->web_url;
    }
}

然后您可以修改您的 get_option() 函数以简单地返回一个对象:

function get_option($keyword) {
    /*
     * The code below is just an example
     * This function must return an object
     */
    return new Value($keyword);
}

您的Padd_Input_Advertisement 构造函数应更新如下:

function __construct($keyword,$name,$description='') {
    $this->keyword = $keyword;
    // removed the unserialize call as it's not necessary anymore
    $this->value = get_option($keyword);
    $this->name = $name;
    $this->description = $description;
}

【讨论】:

  • 正确分析,我们确实需要来自 OP 的更多信息来确认问题的根本原因。
  • 这是错误的,因为unserialize() 返回的是实际对象(有关详细信息,请参阅其文档)。使用中间的Value 类是没有意义的。
【解决方案3】:

我会将此添加为评论,但我想我还没有声望点来做这件事。

您是否尝试过开启错误报告?

error_reporting(E_ALL);
ini_set("display_errors", 1);

【讨论】:

  • 是的,真的没什么有趣的。通常不会显示警告,并且页面上已经显示了致命错误。我收到“致命错误:在非对象上调用成员函数 get_alt_desc()”,我怀疑这是它尝试使用的变量为空白的结果。
  • 看看当你创建一个除了分配 $value 什么都不做的函数时会发生什么。也许暂时公开 $value 并查看您保存到 $value 的对象是否存在并且在您调用该函数后是否可以从 Padd_Input_Advertisement 外部访问。您是否在 Padd_Input_Advertisement 的正确实例上调用 __toString?
  • 这都是 WordPress 主题的一部分。我不确定如何从该文件外部访问其中任何一个。不确定连接了哪些文件等。我不完全确定 PHP 类和东西,但我相信 __toString 会为每个 Padd_Input_Advertisement 实例调用
【解决方案4】:

在面向对象编程中,您必须使用$this 调用函数。 在您的函数__toString() 中,您可以直接调用函数。

所以你已经像这样调用了类的函数

$this->set_name();

【讨论】:

  • 请参阅我的问题中的“编辑 3”。
  • 这是什么 $this->value->get_alt_desc() ?
  • 你能在你的页面中包含另一个函数文件吗?
  • 阅读这篇文章可能会对你有所帮助php.net/manual/en/language.oop5.magic.php#object.sleep
  • 好的,我有你用过的 Php 魔法方法的链接,阅读它可能对你有帮助
【解决方案5】:

使用来自Padd Solutions 的 Magaling 主题,其中包含问题的脚本,我在主题目录的 index.php 中添加了以下代码:

/*********************************TEST***********************************/
  $padd_options[ 'advertisements' ] = array( new Padd_Input_Advertisement( PADD_THEME_SLUG . '_ads_468060_1', 'Banner Ad 1 (468x60)', 'The advertisement is placed beside the site name in the header.' ),
                                             new Padd_Input_Advertisement( PADD_THEME_SLUG . '_ads_468060_2', 'Banner Ad 2 (468x60)', 'The advertisement is placed just below the title in Search Result page, Categories page, Tags page, Author page, and Archives page.' ),
                                             new Padd_Input_Advertisement( PADD_THEME_SLUG . '_ads_125125_1', 'Square Ad 1 (125x125)', 'The advertisement will be posted at the side bar.' ),
                                             new Padd_Input_Advertisement( PADD_THEME_SLUG . '_ads_125125_2', 'Square Ad 2 (125x125)', 'The advertisement will be posted at the side bar.' ),
                                             new Padd_Input_Advertisement( PADD_THEME_SLUG . '_ads_125125_3', 'Square Ad 3 (125x125)', 'The advertisement will be posted at the side bar.' ),
                                             new Padd_Input_Advertisement( PADD_THEME_SLUG . '_ads_125125_4', 'Square Ad 4 (125x125)', 'The advertisement will be posted at the side bar.' ), );

  echo var_dump( $padd_options[ 'advertisements' ] );

/*********************************TEST***********************************/

得到了如下结果,表明该值是一个包含其他几个值的数组:

array (size=6)
  0 => 
    object(Padd_Input_Advertisement)[286]
      protected 'keyword' => string 'magaling_ads_468060_1' (length=21)
      protected 'value' => 
        object(Padd_Advertisement)[282]
          private 'img_url' => string 'http://localhost/TestSite/wp-content/themes/magaling/images/advertisement-468x060.gif' (length=86)
          private 'alt_desc' => string 'Padd Solutions' (length=14)
          private 'web_url' => string 'http://www.paddsolutions.com' (length=28)
          private 'target' => string '_new' (length=4)
          private 'css_class' => string '' (length=0)
      protected 'name' => string 'Banner Ad 1 (468x60)' (length=20)
      protected 'description' => string 'The advertisement is placed beside the site name in the header.' (length=63)
  1 => 
    object(Padd_Input_Advertisement)[284]
      protected 'keyword' => string 'magaling_ads_468060_2' (length=21)
      protected 'value' => 
        object(Padd_Advertisement)[283]
          private 'img_url' => string 'http://localhost/TestSite/wp-content/themes/magaling/images/advertisement-468x060.gif' (length=86)
          private 'alt_desc' => string 'Padd Solutions' (length=14)
          private 'web_url' => string 'http://www.paddsolutions.com' (length=28)
          private 'target' => string '_new' (length=4)
          private 'css_class' => string '' (length=0)
      protected 'name' => string 'Banner Ad 2 (468x60)' (length=20)
      protected 'description' => string 'The advertisement is placed just below the title in Search Result page, Categories page, Tags page, Author page, and Archives page.' (length=131)
  2 => 
    object(Padd_Input_Advertisement)[279]
      protected 'keyword' => string 'magaling_ads_125125_1' (length=21)
      protected 'value' => 
        object(Padd_Advertisement)[278]
          private 'img_url' => string 'http://localhost/TestSite/wp-content/themes/magaling/images/advertisement-125x125.jpg' (length=86)
          private 'alt_desc' => string 'Padd Solutions' (length=14)
          private 'web_url' => string 'http://www.paddsolutions.com' (length=28)
          private 'target' => string '_new' (length=4)
          private 'css_class' => string '' (length=0)
      protected 'name' => string 'Square Ad 1 (125x125)' (length=21)
      protected 'description' => string 'The advertisement will be posted at the side bar.' (length=49)
  3 => 
    object(Padd_Input_Advertisement)[277]
      protected 'keyword' => string 'magaling_ads_125125_2' (length=21)
      protected 'value' => 
        object(Padd_Advertisement)[276]
          private 'img_url' => string 'http://localhost/TestSite/wp-content/themes/magaling/images/advertisement-125x125.jpg' (length=86)
          private 'alt_desc' => string 'Padd Solutions' (length=14)
          private 'web_url' => string 'http://www.paddsolutions.com' (length=28)
          private 'target' => string '_new' (length=4)
          private 'css_class' => string '' (length=0)
      protected 'name' => string 'Square Ad 2 (125x125)' (length=21)
      protected 'description' => string 'The advertisement will be posted at the side bar.' (length=49)
  4 => 
    object(Padd_Input_Advertisement)[275]
      protected 'keyword' => string 'magaling_ads_125125_3' (length=21)
      protected 'value' => 
        object(Padd_Advertisement)[273]
          private 'img_url' => string 'http://localhost/TestSite/wp-content/themes/magaling/images/advertisement-125x125.jpg' (length=86)
          private 'alt_desc' => string 'Padd Solutions' (length=14)
          private 'web_url' => string 'http://www.paddsolutions.com' (length=28)
          private 'target' => string '_new' (length=4)
          private 'css_class' => string '' (length=0)
      protected 'name' => string 'Square Ad 3 (125x125)' (length=21)
      protected 'description' => string 'The advertisement will be posted at the side bar.' (length=49)
  5 => 
    object(Padd_Input_Advertisement)[217]
      protected 'keyword' => string 'magaling_ads_125125_4' (length=21)
      protected 'value' => 
        object(Padd_Advertisement)[216]
          private 'img_url' => string 'http://localhost/TestSite/wp-content/themes/magaling/images/advertisement-125x125.jpg' (length=86)
          private 'alt_desc' => string 'Padd Solutions' (length=14)
          private 'web_url' => string 'http://www.paddsolutions.com' (length=28)
          private 'target' => string '_new' (length=4)
          private 'css_class' => string '' (length=0)
      protected 'name' => string 'Square Ad 4 (125x125)' (length=21)
      protected 'description' => string 'The advertisement will be posted at the side bar.' (length=49)

我不知道为什么您的脚本中的值丢失了,但是您使用的主题或调用函数的方式有一些缺失或错误。顺便说一下,提供的信息还不够.

希望这会有所帮助。

【讨论】:

    【解决方案6】:

    编辑: 是否需要反序列化调用:

    $this->value = unserialize(get_option($keyword));
    

    get_option 已经返回未序列化的对象(只要它是由 update_option() 保存的 - 如果需要,它会在将对象保存到数据库之前自动序列化对象)

    原始答案

    我怀疑问题出在您序列化对象的方式上。

    您需要确保在序列化过程中(转换为字符串表示形式)序列化对象的类型是已知的。只有这样你才能成功地反序列化(从字符串表示转换回对象)它回来。

    回答您关于_toString() 的另一个问题。当您尝试在字符串上下文中使用对象时(例如,当您尝试回显对象时),PHP 会神奇地调用此函数。你不要直接调用这个函数。

    这是演示工作流程的单个 php 文件;用 cmets 到您应该寻找陷阱的部分(问题的原因)。将其保存为 index.php 并运行以查看结果。

    <?php
    error_reporting(E_ALL);
    ini_set('display_errors', '1');
    
    class Padd_Input_Advertisement {
        protected $keyword;
        protected $value;
        protected $name;
        protected $description;
    
        function __construct($keyword,$name,$description='') {
            $this->keyword = $keyword;
            $this->value = unserialize(get_option($keyword));
            $this->name = $name;
            $this->description = $description;        
        }
    
        public function get_keyword()         { return $this->keyword; }
        public function set_keyword($keyword) { $this->keyword = $keyword; }
        public function get_value()           {  return $this->value; }
        public function set_value($value)     { $this->value = $value; }
        public function get_name()            { return $this->name; }
        public function set_name($name)       { $this->name = $name; }
        public function get_description()     { return $this->description;}
        public function set_description($description) { $this->description = $description; }
        public function  __toString() {
    
            $strHTML  = '';
            $strHTML .= '<tr valign="top">';
            $strHTML .= '   <th scope="row"><label for="' . $this->keyword . '">' . $this->name . '</label></th>';
            $strHTML .= '   <td>';
            $strHTML .= '       <label for="' . $this->keyword. '_alt_desc">Short Description</label><br />';
            $strHTML .= '       <input name="' . $this->keyword . '_alt_desc" type="text" id="' . $this->keyword . '_alt_desc" value="' . $this->value->get_alt_desc() . '" size="80" /><br />';
            $strHTML .= '       <label for="' . $this->keyword. '_img_url">Image URL</label><br />';
            $strHTML .= '       <input name="' . $this->keyword . '_img_url" type="text" id="' . $this->keyword . '_img_url" value="' . $this->value->get_img_url() . '" size="80" /><br />';
            $strHTML .= '       <label for="' . $this->keyword. '_web_url">Website</label><br />';
            $strHTML .= '       <input name="' . $this->keyword . '_web_url" type="text" id="' . $this->keyword . '_web_url" value="' . $this->value->get_web_url() . '" size="80" />';
            $strHTML .= '       <br /><small>' . $this->description . '</small>';
            $strHTML .= '   </td>';
            $strHTML .= '</tr>';
            return $strHTML;
        }
    
    }
    
    //Just a sample of the class representing your option object
    class Class_Of_Value {
        protected $alt_desc;
        protected $img_url;
        protected $web_url;
    
        public function __construct($keyword) {
            $this->alt_desc = 'description'; 
            $this->img_url = 'image'; 
            $this->web_url = 'web'; 
        }
    
        public function get_alt_desc() { return $this->alt_desc; }
        public function get_img_url()  { return $this->img_url; } 
        public function get_web_url()  { return $this->web_url; }
    }
    
    //Sample of a CORRECT get_option function.
    function get_option($keyword) {
        //THIS IS IMPORTANT
        $valueObject = new Class_Of_Value($keyword);
        //MAKE SURE THAT TYPE of serialised value is KNOWN
        return serialize($valueObject); 
    }
    //Here is the root cause of your problem.
    //Wordpress' get_option() DOES NOT serialise returned objects. It returns just value of an option pulled from database!
    //Hence you can't call methods  $this->value->get_alt_desc() etc.
    
    
    define ('PADD_NAME_SPACE', ''); //dummy definition of the constant for the sake of PHP Notices
    
    $padd_options['advertisements'] = array(
        new Padd_Input_Advertisement(
            PADD_NAME_SPACE . '_ads_125125_1',
            'Square Ad 1 (125x125)',
            'The advertisement will be posted at the side bar.'
        ),
        new Padd_Input_Advertisement(
            PADD_NAME_SPACE . '_ads_125125_2',
            'Square Ad 2 (125x125)',
            'The advertisement will be posted at the side bar.'
        ),
        new Padd_Input_Advertisement(
            PADD_NAME_SPACE . '_ads_125125_3',
            'Square Ad 3 (125x125)',
            'The advertisement will be posted at the side bar.'
        ),
        new Padd_Input_Advertisement(
            PADD_NAME_SPACE . '_ads_125125_4',
            'Square Ad 4 (125x125)',
            'The advertisement will be posted at the side bar.'
        ),
    );
    
    //Here __toString will be called by PHP outputing your HTML form filled with object values.
    echo($padd_options['advertisements'][0]);
    

    对您的问题的建议解决方案是确保 Wordpress 选项在保存到数据库之前已正确序列化(使用对象类型)(WP 的 update_option())。 因此,get_option 将返回序列化字符串,然后将在您的 __construct 方法中正确反序列化。

    【讨论】:

    • 对象类型 name 总是序列化的,iirc。但是,类型 declaration 必须在反序列化之前可用。 (这与您所说的相反:当然,在序列化时对象的类型是已知的。如果不是这种情况,它就不会被实例化:)
    • 是的,你是对的。但是只有当对象本身也被序列化时,对象类型才会被序列化。我概述的问题是对象可能根本没有序列化。我检查了 Wordpress Codex,它让我找到了另一个答案。
    【解决方案7】:

    您是否尝试强制运算符 -> 优先级?

    我的意思是,从这个:

    $this->value->get_alt_desc()
    

    到这里:

    ($this->value)->get_alt_desc()
    

    也许您的 PHP 解释器正在尝试评估 value-&gt;get_alt_desc()

    【讨论】:

      【解决方案8】:

      所以,我找到了解决这个问题的方法,使代码按预期工作。它不能解决根本原因,但它更像是一种解决方法。

      在我添加的__construct函数中:

      $this->value2 = $this->value;
      

      然后在导致错误的代码中我更改了:

      $this->value->get_alt_desc()
      

      $this->value2->get_alt_desc()
      

      所以所有的代码都在工作,除了一个变量 $this->value 失去了它的价值,一旦我使用了一个不同的变量名,一切都正常工作了。

      【讨论】:

      • -1,因为您决定让问题更加混乱。
      • @SherwinFlight 你不应该接受你的回答。您的问题是“Any idea what could be causing this?”。您的回答没有回答这个问题,而 Nison 的最高票数回答了。
      • 似乎“值”在PHP中有特殊的含义。
      • 这就是解决问题的方法。我想问题是我如何表达我的问题。而不是问“知道是什么原因造成的吗?”我应该问“解决这个问题的最简单方法是什么?”。
      猜你喜欢
      • 2013-03-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-07-15
      • 2021-09-20
      • 2011-12-01
      相关资源
      最近更新 更多