重用PHP嵌套循环结构用于多种用途

时间:2016-11-20 21:25:19

标签: php

我有一个嵌套循环来迭代由不同对象类型组成的数据结构。我想将此循环结构用于多种用途。

我找到了关于how to reuse nested loops in C++的讨论。有没有办法在PHP中重用这个循环结构而不将循环复制到每个不同情况的新函数中?

这是我的代码:

foreach ($this->orders as $order) { // OrderObject
foreach ($order->items as $itemGroup) { // ItemPrice, ItemFees
    foreach ($itemGroup as $item) { // PrincipalItem, PriceItem, FeeItem
        switch (get_class($item)) {
            case 'PrincipalItem':
                $revenue += $item->getAmountAfterTax() * $item->quantity;
                break;
            case 'PriceItem':
                $revenue += $item->getAmountAfterTax();
                break;
            case 'FeeItem':
                $fees += $item->amount;
                break;
        }
    }
}
}

在上面的第一个例子中,我正在总结各种值。在另一个例子中,我想以CSV格式输出数据。相同的循环将实现此目的,我只需要更改开关盒内的线。

2 个答案:

答案 0 :(得分:1)

代码的switch (get_class($item))部分是名为polymorphism的OOP概念的错误实现。

正确的方法是定义一个interface来声明一个方法(让它命名为updateAmounts())然后在你可以拥有的所有类中实现接口{{1在内循环中。 $item方法的每个实现都包含来自updateAmounts()语句的相应case的代码。

这样的事情:

switch

现在嵌套循环看起来像这样:

// This class is a Value Object.
// It doesn't need behaviour and it's OK to have public properties
class Amounts
{
    public $revenue = 0;
    public $fees    = 0;
}

interface HasAmounts
{
    /**
     * Update the revenue and the fees in the passed Amounts object
     * using the data stored in this object.
     */
    public function updateAmounts(Amounts $a);
}

class PrincipalItem implements HasAmounts
{
    public function updateAmounts(Amounts $a)
    {
        $a->revenue += $this->getAmountAfterTax() * $this->quantity;
    }
}

class PriceItem implements HasAmounts
{
    public function updateAmounts(Amounts $a)
    {
        $a->revenue += $this->getAmountAfterTax();
    }
}

class FeeItem implements HasAmounts
{
    public function updateAmounts(Amounts $a)
    {
        $a->fees += $this->amount;
    }
}

如果类$amounts = new Amounts(); foreach ($this->orders as $order) { // OrderObject foreach ($order->items as $itemGroup) { // ItemPrice, ItemFees foreach ($itemGroup as $item) { // PrincipalItem, PriceItem, FeeItem $item->updateAmounts($amounts); } } } echo('Revenue: '.$amounts->revenue."\n"); echo('Fees: '.$amounts->fees."\n"); PrincipalItemPriceItem已经扩展了相同的基类(或具有共同的祖先),则可以添加该方法(如abstract或使用空实现)到这个类(并且不再需要接口)。

在上面的代码转换之后,你还想找到一种方法来重用嵌套的FeeItem块吗?

foreach声明现在看起来不值得重用。发生这种情况是因为值得重用的代码被移动到它所属的位置;代码应该与它处理的数据保持在一起。

通过移动包含其操作数据的类中的每个foreach,可以对代码进行进一步的重构。

例如:

foreach

如果class OrderObject implements HasAmounts { public function updateAmounts(Amounts $a) { foreach ($this->items as $itemGroup) { // ItemPrice, ItemFees foreach ($itemGroup as $item) { // PrincipalItem, PriceItem, FeeItem $item->updateAmounts($amounts); } } } } 是某个类(或更多)的对象,那么内部$itemGroup可以移动到这些类中的每一个(在foreach方法的实现中)代码与它处理的数据保持在同一个类中的方式(它被称为encapsulation,它是OOP代码的另一个重要属性)。

现在调用代码现在看起来像这样:

updateAmounts()

看,妈!没有嵌套的$amounts = new Amounts(); foreach ($this->orders as $order) { // OrderObject $order->updateAmounts($amounts); } echo('Revenue: '.$amounts->revenue."\n"); echo('Fees: '.$amounts->fees."\n"); 循环

我担心我会破坏你的嵌套foreach循环,没有什么可以重用它。

但是等等!你的类现在包含行为(它们可能只是数据的无定形容器),这比编写通用代码更好(因为它似乎是你重用foreach循环的目标)。因为这就是OOP应该是:数据和代码打包在一起。

答案 1 :(得分:0)

如果您想多次使用某段代码,请制作functions。然后可以执行那些。这是函数的manual

示例:

<?php
function example($itemGroup,$orders,$items){

    foreach ($orders as $order) { // OrderObject
        foreach ($items as $itemGroup) { // ItemPrice, ItemFees
            foreach ($itemGroup as $item) { // PrincipalItem, PriceItem, FeeItem
                switch (get_class($item)) {
                    case 'PrincipalItem':
                        $revenue += $item->getAmountAfterTax() * $item->quantity;
                        break;
                    case 'PriceItem':
                        $revenue += $item->getAmountAfterTax();
                        break;
                    case 'FeeItem':
                        $fees += $item->amount;
                        break;
                }
            }
        }
    }
}

example($value,$oders,$items);
?>

您现在可以在任何地方调用此example。如果您在OOP写作,请参阅手册。

如前所述,您还可以将functions存储在variable中,这些名为Anonymous functions。以下是对manual

的引用

实施例

<?php   
$var = function($variable){
    echo "this is a function with a ".$variable;
}

$var("variable");
?>

您可以调用代码中显示的那些函数。

所有这些都会导致你的答案,你可以把它们融合在一起,就像这样。

实施例

<?php

function test( callable $function){
    $function();
}

test(function(){
    echo "some code";
})

?>

在您的情况下:

<?php
function example($itemGroup,$orders,$items,$function()){

    foreach ($orders as $order) { // OrderObject
        foreach ($items as $itemGroup) { // ItemPrice, ItemFees
            foreach ($itemGroup as $item) { // PrincipalItem, PriceItem, FeeItem
                $function();
            }
        }
    }

}

example($itemGroup,$orders,$items,function(){

    switch (get_class($item)) {
        case 'PrincipalItem':
            $revenue += $item->getAmountAfterTax() * $item->quantity;
            break;
        case 'PriceItem':
            $revenue += $item->getAmountAfterTax();
            break;
        case 'FeeItem':
            $fees += $item->amount;
            break;
    }

}
?>