douyin9987 2014-09-30 06:18
浏览 20
已采纳

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

I have the following code in 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'
            ]
        ];
    }
}

Doing the following

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

must give me the following output

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

Does anyone know how to achieve this?

Anyone can extend class A and I don't want other users to manually use array_merge_recursive for achieving this.

Thanks in advance

  • 写回答

2条回答 默认 最新

  • duan36000 2014-09-30 07:26
    关注

    You can have a class in the middle that does the work. It should have another method that will be inherited and later used. The only condition here is to not use foo() in public, but getFoo() instead

    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());
    

    This could also be achieved making foo() protected and a magic __call() method which does the work of getFoo(). Then calling $b->foo() will trigger __call() thus resulting in merging that parent and this contexts of foo() and spitting them out.

    By the way, array merge recursive will not result into the exactly the same output you do want, anyway, you can do whatever logic you need in getFoo() (or in __call())

    A problem here could be that if foo() has lower access modifier than public you cannot have it in an interface. Luckily, abstract classes could have abstract protected methods which will obligate the childred to implement this method.

    A sample scenario of the __call() way and obligating members to have protected foo() could be:

    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());
    

    This way B will have some problems with autocompletion of foo. If One does not know the "hack" when writing $b-> will not recieve suggestion for foo(). A little more hacks can resolve this in at least Netbeans and PHPStorm

    Annotating that Middle has a public foo() method before definition of Middle class:

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

    Later annotating that the instance of B is actually an instance of Middle:

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

    Afterwards writing $b-> will result into suggesting the foo() method.

    It might be better if there is another class that inherits B and has no methods, but only annotations, but as I understood, classes like B will be written from other people and they might not be familiar with this convention.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥35 平滑拟合曲线该如何生成
  • ¥100 c语言,请帮蒟蒻写一个题的范例作参考
  • ¥15 名为“Product”的列已属于此 DataTable
  • ¥15 安卓adb backup备份应用数据失败
  • ¥15 eclipse运行项目时遇到的问题
  • ¥15 关于#c##的问题:最近需要用CAT工具Trados进行一些开发
  • ¥15 南大pa1 小游戏没有界面,并且报了如下错误,尝试过换显卡驱动,但是好像不行
  • ¥15 自己瞎改改,结果现在又运行不了了
  • ¥15 链式存储应该如何解决
  • ¥15 没有证书,nginx怎么反向代理到只能接受https的公网网站