用PHP设计噩梦

时间:2013-08-03 23:17:54

标签: php class design-patterns

我已经尝试了很长时间才能找到一个使用PHP来实现我想要的正确设计,但是我尝试过的所有内容都失败了,我猜这可能是因为我没有从正确的角度看所以我希望你们中的一些人能够启发我并给我一些好的建议!

一开始设计看起来有点奇怪,但我向你保证并不是因为我喜欢让事情复杂化。为了简单起见,我只给出了问题的最小结构,而不是实际的代码。它从这些开始:

<?php

// ------------------------------------------------------------------------

class Mother_A
{
    const _override_1 = 'default';
    protected static $_override_2 = array();

    public static function method_a()
    {
        $c = get_called_class();
        // Uses $c::_override_1 and $c::$_override_2
    }
}

// ------------------------------------------------------------------------

class Mother_B extends Mother_A
{
    public function method_b()
    {
        // Uses self::method_a()
    }
}

Mother_A定义了一个静态方法,它使用常量和静态来被子项覆盖。这允许在派生类Mother_B中定义泛型方法(相当于“模板”方法)。 Mother_AMother_B都不打算实例化,但Mother_B不应该是抽象的。这利用了Late Static Binding,我发现它非常有用。

现在出现了我的问题。我想在n个不同的“情境”(情况1,情境2等)中定义两个类:

<?php 

// ------------------------------------------------------------------------

class Child_A_Situation_k extends Mother_A
{
    // Uses method_a
}

// ------------------------------------------------------------------------

class Child_B_Situation_k extends Mother_B
{
    // Uses method_a and method_b
}

当然,我实际上并没有给出这些愚蠢的名字;这两个类在每种情况下都有不同的名称,但都遵循Mother_AMother_B中相同的派生模式。但是,在每个单独的情况下('情境'),两个类都需要完全相同的常量/静态覆盖,并且我不知道如何在不重复两个类中的覆盖的情况下执行此操作。 / p>


我尝试了很多东西,但是我得到的最接近的是实现了一个接口Interface_Situation_k,它定义了情境k的常量和静态,并让两个孩子都实现了这个接口。当然,你不能在界面中定义静态,所以它失败了,但你明白了。我会交换一个类的接口,但是PHP中没有多重继承,所以它也无效。 :/我真的被卡住了,我迫不及待想要阅读一个可能的解决方案!提前谢谢!

1 个答案:

答案 0 :(得分:1)

这是我能做的最好的事情,我认为没有办法用更少的代码来做到这一点。 查看代码中的注释以获取更多信息。

完全正常工作的代码:

<?php

class Mother_A
{
    // you're using '_override_1' as a variable, so its obviously not a constant
    // also i made it public for the setSituation function, 
    // you could keep it protected and use reflections to set it
    // but i dont really see a reason for that. 
    // if you want that, look up how to set private/protected variables
    public static $_override_1 = 'default'; 
    public static $_override_2 = array();

    public static function method_a()
    {
        $c = get_called_class();
        var_dump($c::$_override_1);
        var_dump($c::$_override_2);
        // Uses $c::_override_1 and $c::$_override_2
    }

    public static function setSituation($className)
    {
        $c = get_called_class();
        // iterate through the static properties of $className and $c 
        // and when the you find properties with the same name, set them
        $rBase = new ReflectionClass($c);
        $rSituation = new ReflectionClass($className);
        $staBase = $rBase->getStaticProperties();
        $staSituation = $rSituation->getStaticProperties();
        foreach($staSituation as $name => $value)
        {
            if(isset($staBase[$name])) $c::$$name = $value;
        }
    }
}

// ------------------------------------------------------------------------

class Mother_B extends Mother_A
{
    public function method_b()
    {
        self::method_a();
    }
}

class Situation_k
{
    public static $_override_1 = 'k';
    public static $_override_2 = array('k','k');
}

class Child_A_Situation_k extends Mother_A { }
Child_A_Situation_k::setSituation('Situation_k'); 
// This is not as short as writing 'extends Mother_A, Situation_k'
// but i think you wont get it shorter

class Child_B_Situation_k extends Mother_B { }
Child_B_Situation_k::setSituation('Situation_k');

echo '<pre>';
Child_A_Situation_k::method_a();
echo "\n";
Child_B_Situation_k::method_a();
echo "\n";
Child_B_Situation_k::method_b();
echo "\n";
echo '</pre>';
?>