Подтвердить что ты не робот

Контекст метода метода 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 этого еще не делает. Дайте мне помягче.

Спасибо!

4b9b3361

Ответ 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() {}
}