带有受保护数组属性的 php 继承让我很头疼

Posted

技术标签:

【中文标题】带有受保护数组属性的 php 继承让我很头疼【英文标题】:php inheritance with protected array property is giving me a serious headache 【发布时间】:2013-12-29 23:57:36 【问题描述】:

所以我决定在 php 中创建一些类,这样我就可以使用

、 和 标签动态构建菜单栏。原因是因为我想跨项目重用它。

首先是代码块,请注意我在代码中添加了一些调试信息,因为我实际上是一名 .NET 开发人员,但我还不知道如何体面地调试:s

<?php

// Menu Items <li><a href=\"$target\">$itemName</a></li>
class MenuItem 
    public $order;
    public $target;
    public $itemName;

function __construct($itemName="", $target="", $order=0) 
    $this->order = $order;
    $this->target = $target;
    $this->itemName = $itemName;


public function Build() 
    //if $target is empty or $itemName is empty then return empty string (both must be present to generate an item)
    if(strcasecmp($target,"") == 0 || strcasecmp($itemName,"") == 0)  
        return "";
    
    return "<li><a href=\"" . $target . "\">" . $itemName . "</a></li>";



//<li><a>$FirstMenuItem</i>
// Submenu Root Head Item: <li><a href=\"$(optional)Target\">$ItemName</a><ul>
// Holds a list of MenuItems and SubmenuRootItems
// Submenu Root End Item: </ul>
class SubMenu extends MenuItem 
    protected $itemArray;

    function __construct($itemName = "", $target = "", $order = 0) 
        parent::__construct($itemName, $target, $order);
        $this->itemArray = array();
    

    public function Items() 
        return $this->itemArray;
    

    public function AddSubMenuItem ($subMenuItem) 
        $retval = strcasecmp( get_class ($subMenuItem), "submenu") == 0 ? self::AddItem($subMenuItem) : false;
       echo"<br>second dump<br>";
        var_dump($this->itemArray); echo "<br>";
        return $retval;
    

    public function AddMenuItem ($menuItem) 
        $retval =  strcasecmp( get_class ($menuItem), "menuitem") == 0 ? self::AddItem($menuItem) : false;
        echo"<br>second dump<br>"; //debug code
        var_dump($this->itemArray); echo "<br>"; //debug code
        return $retval;
    

    protected function AddItem($item) 
        $itemArray[$item->itemName] = $item;
        echo "AddItem <br />"; //ugly debug code
        var_dump($itemArray); //even more of it
        return true;
    

    public function Build() 
        $buildhtml = "<li>";
        $buildHtml .= strcasecmp($target, "") == 0 ?  "<a>" : "<a href=\"" . $target . "\">";
        $buildHtml .= $itemName . "</a><ul>";
        $buildHtml .= BuildSubMenu(Items());
        $buildHtml .= "</ul></li>";
    

    public function BuildSubMenu($menuItems) 
        $buildHtml = "";
        echo "for each start". var_dump($menuItems) ;
        foreach($menuItems as $menuItem) 
            echo $menuItem;
            $buildHtml .= $menuItem->Build();
        

        return $buildHtml;
    


// Menu Root Element <ul id=\"menu\">
// holds a list of MenuItems and SubmenuRootItems
// Menu Root Closing Element </ul>
class MenuBuilder extends SubMenu 
    function __construct() 
        parent::__construct(); 
    

    public function Build()   echo "<br><br><br>". var_dump($this->itemArray); echo "<br><br><br>".var_dump(parent::$this->itemArray);echo "<br><br><br>";//ugly debug code

        $buildHtml = "<ul id=\"menu\">";
        $buildHtml .= parent::BuildSubMenu($this->itemArray);
        $buildHtml .= "</ul>";

        return $buildHtml;
    

?>

问题是整个事情都不起作用,php 显然不是 .NET,但我真的不知道以下内容是如何成立的。为了测试,我制作了这个小 php 页面,它对我的​​新类进行了一些调用。

Write("Create menuBuilder...");
$menuBuilder = new MenuBuilder();
WriteLine("Done!");

Write("Create subMenu1...");
$subMenu1 = new SubMenu("Sub Menu 1");
WriteLine("Done!");

Write("Execute subMenu1->AddMenuItem...");
$subMenu1->AddMenuItem(new MenuItem("Menu Item 1.1", "#1.1"));
WriteLine("Done!");

Write("Create menuItem2...");
$menuItem2 = new MenuItem("Menu Item 2","#2");
WriteLine("Done!");

Write("Execute menuBuilder->AddSubMenuItem...");
$menuBuilder->AddSubMenuItem($subMenu1);
WriteLine("Done!");
Write("Execute menuBuilder->AddMenuItem...");
$menuBuilder->AddMenuItem($menuItem2);
WriteLine("Done!");

然后在 $subMenu 和 $menuBuilder 上都有 Items 属性的转储

这些调用在我的浏览器中的输出完全让我感到困惑:

Create menuBuilder...Done!
Create subMenu1...Done!
Execute subMenu1->AddMenuItem...AddItem 
array(1)  ["Menu Item 1.1"]=> object(MenuItem)#4 (3)  ["order"]=> int(0) ["target"]=>    string(4) "#1.1" ["itemName"]=> string(13) "Menu Item 1.1"   
second dump
array(0)   
Done!
Create menuItem2...Done!
Execute menuBuilder->AddSubMenuItem...AddItem 
array(1)  ["Sub Menu 1"]=> object(SubMenu)#3 (4)  ["itemArray":protected]=> array(0)   ["order"]=> int(0) ["target"]=> string(0) "" ["itemName"]=> string(10) "Sub Menu 1"   
second dump
array(0)   
Done!
Execute menuBuilder->AddMenuItem...AddItem 
array(1)  ["Menu Item 2"]=> object(MenuItem)#4 (3)  ["order"]=> int(0) ["target"]=> string(2) "#2" ["itemName"]=> string(11) "Menu Item 2"   
second dump
array(0)   
Done!

所以 AddItem 函数起作用了,一个项目被添加到 $itemArray 并且它被成功转储。然后当函数返回它的调用者'AddMenuItem'并且我再次转储相同的 $itemArray 时它是空的?我真的不明白这是如何工作的:s

【问题讨论】:

我忘了说的是最终目标。我希望从代码和示例中可以清楚地看到。最终目标是让我的 $menuBuilder 实例,动态添加项目,最后调用 build 方法来取回我的 HTML 代码。噗菜单创建:) $itemArray 不是$this-&gt;itemArray 【参考方案1】:

也许您不会更改 AddItem 方法中的类 itemArray 属性?

你有这个:

protected function AddItem($item) 
    $itemArray[$item->itemName] = $item;
    echo "AddItem <br />"; //ugly debug code
    var_dump($itemArray); //even more of it
    return true;

试试这个:

protected function AddItem($item) 
    // $this will change the class property :)
    $this->itemArray[$item->itemName] = $item;
    echo "AddItem <br />"; //ugly debug code
    var_dump($this->itemArray); //even more of it
    return true;

你不会在很多地方使用 $this,比如在 MenuItem->Build 方法中:

class MenuItem 
    public $order;
    public $target;
    public $itemName;

function __construct($itemName="", $target="", $order=0) 
    $this->order = $order;
    $this->target = $target;
    $this->itemName = $itemName;


public function Build() 
    // The $target and $itemName variables aren't inicialized
    //if $this->target is empty or $this->itemName is empty then return empty string (both must be present to generate an item)
    if(strcasecmp($this->target,"") == 0 || strcasecmp($this->itemName,"") == 0)  
        return "";
    
    return "<li><a href=\"" . $this->target . "\">" . $this->itemName . "</a></li>";


【讨论】:

也改变var_dump参数 在其他几个地方似乎也缺少 $this。 它确实解决了这个问题,但似乎我不得不在很多这些项目上使用 $this-> 运算符。我一起删除了 var_dumps,我只是插入它们以获得一些额外的调试信息。我现在确实得到了一些没有崩溃的输出,但它还不正确。 '$itemArray' 应该包含两个子菜单项作为菜单项。我要创建的结构应该是一个带有子菜单的菜单,它可以包含更多的子菜单或项目。此外,项目也应该能够成为菜单的一部分。 递归调用呢? php可以处理这些吗?因为我递归地调用“BuildSubMenu”,而他应该处理的项目不在我的输出中。 (我当前的输出菜单项2) 对不起,垃圾邮件,但在我的情况下,预期的输出是: Sub Menu 1菜单项 1.1 菜单项 2

以上是关于带有受保护数组属性的 php 继承让我很头疼的主要内容,如果未能解决你的问题,请参考以下文章

带有受保护字段的微妙 C++ 继承错误

多态性和受保护的继承问题

这。与基地。对于继承的受保护的非虚拟方法?

子类公有继承不能访问父类受保护属性? cannot access protected member

“属性在此上下文中受保护”具有继承和 .h 和 .cpp 文件

PHP面向对象 封装与继承