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条)

报告相同问题?

悬赏问题

  • ¥15 素材场景中光线烘焙后灯光失效
  • ¥15 请教一下各位,为什么我这个没有实现模拟点击
  • ¥15 执行 virtuoso 命令后,界面没有,cadence 启动不起来
  • ¥50 comfyui下连接animatediff节点生成视频质量非常差的原因
  • ¥20 有关区间dp的问题求解
  • ¥15 多电路系统共用电源的串扰问题
  • ¥15 slam rangenet++配置
  • ¥15 有没有研究水声通信方面的帮我改俩matlab代码
  • ¥15 ubuntu子系统密码忘记
  • ¥15 保护模式-系统加载-段寄存器