У меня есть следующий код в 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
для достижения этого.
заранее спасибо
Вы можете иметь класс в середине, который делает работу. У него должен быть другой метод, который будет унаследован и позже использован. Единственное условие здесь — не использовать 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
Вы не можете иметь это в интерфейсе. К счастью, абстрактные классы могут иметь абстрактные защищенные методы, которые обязывают дочерний объект реализовать этот метод.
Пример сценария __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.
Если один не знает «взломать» при написании $b->
не получит предложение для foo()
,
Немного больше хаков может решить эту проблему как минимум Netbeans
а также PHPStorm
Аннотируя это Middle
имеет общественность foo()
метод до определения Middle
учебный класс:
/**
* @method foo
*/
class Middle extends A {
Позже, комментируя, что случай B
на самом деле является примером Middle
:
$b = new B();
/* @var $b Middle */
Потом писать $b->
приведет к предложению foo()
метод.
Может быть лучше, если есть другой класс, который наследует B
и не имеет методов, но только аннотации, но, как я понял, классы, как B
будут написаны от других людей, и они могут быть не знакомы с этим соглашением.
Вы можете попробовать это:
<?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) {[«a»] => string (12) «some value 2» [«b»] => string (10) «some
value «[» c «] => array (3) {[» ca «] => string (12)» some value 3 «[» cb «] =>
string (12) «некоторое значение 4» [«cc»] => string (10) «некоторое значение»}}