在扩展类中递归地合并数组

时间:2014-09-30 06:18:24

标签: php arrays multidimensional-array array-merge

我在php中有以下代码:

<?php
interface someInterface {
    public function foo();
}

class A implements someInterface {
    public function foo(){
        return [
            'a' => 'some value',
            'b' => 'some value',
            'c' => [
                'ca' => 'some value',
                'cb' => 'some value',
                'cc' => 'some value'
            ]
        ];
    }
}

class B extends A {
    public function foo(){
        return [
            'a' => 'some value 2',
            'c' => [
                'ca' => 'some value 3',
                'cb' => 'some value 4'
            ]
        ];
    }
}

执行以下操作

$b = new B();
var_dump($b->foo());

必须给我以下输出

[
    'a' => 'some value 2',
    'b' => 'some value',
    'c' => [
        'ca' => 'some value 3',
        'cb' => 'some value 4',
        'cc' => 'some value'
    ]
]

有谁知道如何实现这个目标?

任何人都可以延长class A,我也不希望其他用户手动使用array_merge_recursive来实现这一目标。

提前致谢

2 个答案:

答案 0 :(得分:1)

你可以让中间的班级完成这项工作。它应该有另一个将被继承并随后使用的方法。这里唯一的条件是不在公开场合使用foo(),而是getFoo()而不是

interface someInterface {
    public function foo();
}


class A implements someInterface {
    public function foo(){
        return [
            'a' => 'some value',
            'b' => 'some value',
            'c' => [
                'ca' => 'some value',
                'cb' => 'some value',
                'cc' => 'some value'
            ]
        ];
    }
}

class Middle extends A {
    public function getFoo() {
        return array_merge_recursive(parent::foo(), $this->foo());
    }
}

class B extends Middle {
    public function foo(){
        return [
            'a' => 'some value 2',
            'c' => [
                'ca' => 'some value 3',
                'cb' => 'some value 4'
            ]
        ];
    }
}

$b = new B();
var_dump($b->getFoo());

这也可以通过foo()受保护以及执行__call()工作的神奇getFoo()方法来实现。然后调用$b->foo()会触发__call(),从而导致合并parent this foo()的上下文并将其吐出。

顺便说一下,数组合并递归不会产生你想要的完全相同的输出,无论如何,你可以在getFoo()(或__call())中做你需要的任何逻辑

这里的问题可能是,如果foo()的访问修饰符低于public,则您无法在界面中拥有它。幸运的是,抽象类可能有抽象的受保护方法,这些方法将强制childred实现此方法。

__call()方式和义务成员拥有protected foo()的示例方案可能是:

abstract class Base {
    abstract protected function foo();
}

abstract class A {
    protected function foo(){
        return [
            'a' => 'some value',
            'b' => 'some value',
            'c' => [
                'ca' => 'some value',
                'cb' => 'some value',
                'cc' => 'some value'
            ]
        ];
    }
}

class Middle extends A {
    public function __call($name, $args) {
        if ($name == 'foo')
            return array_merge_recursive(parent::foo(), $this->foo());
    }
}

class B extends Middle {
    protected function foo(){
        return [
            'a' => 'some value 2',
            'c' => [
                'ca' => 'some value 3',
                'cb' => 'some value 4'
            ]
        ];
    }
}

$b = new B();
var_dump($b->foo());

这样B会自动完成foo的一些问题。 如果一个人不知道&#34; hack&#34;撰写$b->时,不会收到foo()的建议。 多一点黑客可以至少在NetbeansPHPStorm

中解决此问题

在定义Middle类之前注释foo()有公共Middle方法:

/**
 * @method foo
 */
class Middle extends A {

稍后注释B的实例实际上是Middle的实例:

$b = new B();
/* @var $b Middle */

之后写$b->会导致建议使用foo()方法。

如果有另一个类继承B并且没有方法但只有注释,那可能会更好,但据我所知,像B这样的类将会从其他人那里编写而他们可能不会熟悉这个惯例。

答案 1 :(得分:0)

你可以试试这个:

<?php

interface someInterface
{
    public function foo();
}

class A implements someInterface
{
    public function foo()
    {
        return [
            'a' => 'some value',
            'b' => 'some value',
            'c' => [
                'ca' => 'some value',
                'cb' => 'some value',
                'cc' => 'some value'
            ]
        ];
    }
}

class B extends A
{
    public function foo()
    {
        $parent = parent::foo();
        $arr = [

            'a' => 'some value 2',
            'c' => [
                'ca' => 'some value 3',
                'cb' => 'some value 4'
            ]
        ];


        return $this->mergeArrays($arr, $parent);

    }

    private function mergeArrays($ar1, $ar2)
    {
        foreach ($ar1 as $key => $item) {
            if (is_array($item)) {
                if (isset($ar2[$key])) {
                    $ar2[$key] = $this->mergeArrays($item, $ar2[$key]);
                } else {
                    $ar2[$key] = $item;
                }
            } else {
                $ar2[$key] = $item;
            }
        }
        return $ar2;
    }

}


$b = new B();
var_dump($b->foo());

输出:

  

array(3){[&#34; a&#34;] =&gt; string(12)&#34; some value 2&#34; [&#34; B&#34;] =&GT;字符串(10)&#34;一些   值&#34; [&#34; C&#34;] =&GT; array(3){[&#34; ca&#34;] =&gt; string(12)&#34; some value 3&#34; [&#34; CB&#34;] =&GT;   string(12)&#34; some value 4&#34; [&#34; CC&#34;] =&GT; string(10)&#34; some value&#34; }}