Контекст метода метода PHP: черта "наследование" и иерархии признаков
ОБНОВЛЕНИЕ: Я не одинок в своих размышлениях по этой проблеме, и кажется, что это действительно ошибка. См. здесь. День, когда он будет установлен, будет фантастическим днем!:)
Это началось как I love PHP traits! I'm going to use them everywhere! ^_^
, и теперь оно превратилось в Thought Exercise / Learning Experience >_<
.
Рассмотрим следующий пример:
trait TheErrorOfYourWays{
public function booboo(){
echo 'You had a booboo :(';
}
}
trait SpectacularStuff1 {
use TheErrorOfYourWays;
}
trait SpectacularStuff2 {
use TheErrorOfYourWays;
}
class DoSomethingSpectacular {
use SpectacularStuff1, SpectacularStuff2;
}
В результате ( очевидно не так очевидно):
Неустранимая ошибка: метод привязки booboo не применяется, потому что на DoSomethingSpectacular есть столкновения с другими методами trait.
Итак, мой вопрос: как разрешить конфликты методов в чертах? Можно ли добиться наложения наследования "наследования"? Если да, то каков "правильный" способ сделать это?
Почему я хочу это сделать:
- Я хочу создать автономные черты и классы (стиль смешивания и соответствия). Если это вообще возможно, я хочу сказать "использовать", а затем волшебные вещи должны произойти. Нет, чтобы почесать голову и подумать: "Теперь какое пространство имен было этой чертой снова?" И т.д. И т.д.
- Не нужно редактировать классы и черты "на лету", когда я делаю что-то "предприимчивое" и обнаруживаю, что я случайно создал конфликт.
- В то время казалось хорошей идеей.
Что я пробовал:
- Руководство по PHP.
- Google.
- В том числе этот вопрос → Не правильный ответ для этого сценария.
- Обнаружено это, но я использую PHP версию 5.5.1. Это исправлено, верно? Правильно?
-
Фантастический массив "как", алиасы, даже вместо, в разных местах, временах, вселенных и т.д. Включая, но не ограничиваясь:
trait SpectacularStuff1 {
use TheErrorOfYourWays{
TheErrorOfYourWays::booboo as booboo1;
}
}
trait SpectacularStuff2 {
use TheErrorOfYourWays{
TheErrorOfYourWays::booboo as booboo2;
}
}
class DoSomethingSpectacular {
use SpectacularStuff1, SpectacularStuff2 {
/* Tried separately, but included here for brevity sake */
SpectacularStuff1::booboo as booboo3;
SpectacularStuff2::booboo as booboo4;
}
}
и
use TheErrorOfYourWays as Erroneous1;
trait SpectacularStuff1 {
use Erroneous1{
Erroneous1::booboo as booboo1;
}
}
use TheErrorOfYourWays as Erroneous2;
trait SpectacularStuff2 {
use Erroneous2{
Erroneous2::booboo as booboo2;
}
}
Я понимаю, что:
- Я могу изменить TheErrorOfYourWays для класса и сделать booboo() static, но я хотел бы узнать об этом конкретном признаке поведения.
- Я могу удалить TheErrorOfYourWays из свойств и использовать его в классе, но это вряд ли "самодостаточно". Каждый раз, когда я использую черты, которые я должен помнить, использовать TheErrorOfYourWays в классе, даже если я не вызываю booboo() непосредственно из класса. Звучит опасно.
- Я, вероятно, допустил некоторую ошибку синтаксиса новобранец или не смог понять псевдониму на глубоком уровне. Если да, пожалуйста... объясните... медленно...
- Возможно, лучший способ сделать это. Если да, пожалуйста... объясните... медленно...
- Я могу быть преждевременным энтузиазмом, и PHP этого еще не делает. Дайте мне помягче.
Спасибо!
Ответы
Ответ 1
Таким образом, неофициальный "официальный" ответ :
Вы можете сделать это без наложения псевдонимов, а не на что-нибудь! Но еще не...
Я обновил с 5.5.1 до 5.5.6, но все тщетно. Если я помню, я обновлю этот ответ, когда исправление станет доступным. Для чего-то вроде рабочего, интересно отметить, что вы можете напрямую вызвать статические функции. Следующий пример работает:
trait TheErrorOfYourWays{
public static function booboo($thisTrait){
echo 'You had a booboo :( in '.$thisTrait.'<br>';
}
}
trait SpectacularStuff1 {
public function boobooTest1(){
TheErrorOfYourWays::booboo(__TRAIT__);
}
}
trait SpectacularStuff2 {
public function boobooTest2(){
TheErrorOfYourWays::booboo(__TRAIT__);
}
}
class DoSomethingSpectacular {
use SpectacularStuff1, SpectacularStuff2;
}
$boobooAChoo = new DoSomethingSpectacular();
$boobooAChoo->boobooTest1(); // You had a booboo :( in SpectacularStuff1
$boobooAChoo->boobooTest2(); // You had a booboo :( in SpectacularStuff2
Да, да, вы также можете сделать это с классом, но классы в прошлом сезоне являются soooo.
Ответ 2
Вам нужно использовать ключевое слово insteadof
для разрешения конфликтов в чертах.
Source
Переписывание
class DoSomethingSpectacular {
use SpectacularStuff1, SpectacularStuff2 {
/* Tried separately, but included here for brevity sake */
SpectacularStuff1::booboo as booboo3;
SpectacularStuff2::booboo as booboo4;
}
}
до
class DoSomethingSpectacular {
use SpectacularStuff1, SpectacularStuff2
{
SpectacularStuff1::booboo insteadof SpectacularStuff2;
SpectacularStuff2::booboo insteadof SpectacularStuff1;
}
}
разрешит конфликты.
Ответ 3
Я нашел еще один способ временно установить это:
trait A {
public function foo(){
echo 'foo';
}
}
trait B {
public function foofoo(){
return $this->foo () . 'foo';
}
}
trait C {
public function foobar(){
return $this->foo () . 'bar';
}
}
class DoSomethingSpectacular {
use A, B, C;
public function foobarfoofoo () {
echo $this->foobar () . $this->foofoo ();
}
}
И он работает:)
Ответ 4
Немного взломайте, просто добавьте функцию booboo
в класс DoSomethingSpectacular
<?php
trait TheErrorOfYourWays{
public function booboo(){
echo 'You had a booboo :(';
}
}
trait SpectacularStuff1 {
use TheErrorOfYourWays{
TheErrorOfYourWays::booboo as booboo1;
}
}
trait SpectacularStuff2 {
use TheErrorOfYourWays{
TheErrorOfYourWays::booboo as booboo2;
}
}
class DoSomethingSpectacular {
use SpectacularStuff1, SpectacularStuff2 {
/* Tried separately, but included here for brevity sake */
SpectacularStuff1::booboo as booboo3;
SpectacularStuff2::booboo as booboo4;
}
//very ugly hack
public function booboo() {}
}