Привет, ребята, я создавал пакет, и я безуспешно пытался внедрить инъекцию зависимостей в моем классе. Я следовал всем инструкциям, чтобы они работали. Я с ума сошел. Когда я пытаюсь позвонить
Player::team_players(2);
это заставило меня ошибиться:
Аргумент 1, переданный в Team \ Player \ Player :: __ construct (), должен быть экземпляром Team \ Player \ StatusPlayerInterface, не указанным в C: \ wamp \ www \ ultima \ workbench \ team \ player \ src \ Team \ Player \ PlayerServiceProvider.php в строке 35 и определяется
Я создал свой класс Player.php
<?php namespace Team\Player; use Team\Player\Models\User; use Team\Player\Models\Team; use Team\Player\Models\Fighter; use Team\Player\StatusPlayerInterface; use DB; class Player { protected $player; function __construct(StatusPlayerInterface $player) { $this->player = $player; } public function team_players($team_id) { return $player->team($team_id); } }
StatusPlayerInterface.php
<?php namespace Team\Player; interface StatusPlayerInterface { public function team($team_id); // active - retired - injured by team id }
Active.php
<?php namespace Team\Player; use Team\Player\Models\User; use Team\Player\Models\Team; use Team\Player\Models\Fighter; /** * */ class Active implements StatusPlayerInterface { protected $user; protected $team; protected $fighter; function __construct(User $user,Team $team,Fighter $fighter) { $this->user = $user; $this->team = $team; $this->fighter = $fighter; } public function team($team_id) { return $fighters = $this->fighter->with('user')->where('team_id',$team_id)->active()->Confirmed()->get(); } }
PlayerServiceProvider.php
public function register() { $this->app->bind('Team\Player\StatusPlayerInterface','Team\Player\Player'); // bind the interface $this->app['player'] = $this->app->share(function($app) { return new Player; // line 35 }); $this->app->booting(function() { $loader = \Illuminate\Foundation\AliasLoader::getInstance(); $loader->alias('Player', 'Team\Player\Facades\Player'); }); }
РЕДАКТИРОВАТЬ:
То, что я пытаюсь сделать, – следовать принципу, который Джеффри Уэй предложил следовать. Он говорит, что объекты должны быть открыты для расширения, но закрыты для модификации.
I 2 других класса, которые реализуют StatusPlayerInterface и, конечно, меняют только запрос в команде функции ()
Тогда у меня есть основной класс Player, а с помощью метода team_players он должен автоматически вызывать функциональную команду вызванного экземпляра. этот метод используется для не
class Player { .... function team_player($team_id,$status) { if (is_a($status) == "Active") { $fighters = $this->fighter->with('user')->where('team_id',$team_id)->active()->Confirmed()->get(); } elseif(is_a($status) == "Retired") { $fighters = $this->fighter->with('user')->where('team_id',$team_id)->retired()->Confirmed()->get(); } // ecc } }
но я могу передать интерфейс конструктору и вернуть только функциональную команду интерфейса, потому что интерфейс подобен контракту, поэтому он может доверять существующей этой функции. Но проблема в том, что я не могу найти способ передать этот интерфейс в конструкторе.
Ваш конструктор здесь ждет $ player:
class Player { ... function __construct(StatusPlayerInterface $player) { $this->player = $player; } }
Поэтому ваш ServiceProvider должен передать один из них в строке 35:
return new Player; // line 35
Я вижу, что вы пытались использовать IoC для этого:
$this->app->bind('Team\Player\StatusPlayerInterface','Team\Player\Player');
Но у вас есть две проблемы,
1) Team\Player\Player
не реализует Team\Player\StatusPlayerInterface
и он должен. Но Active
класс действительно реализует, разве вы не должны его использовать?
2) Я не уверен, что IoC будет эффективен в этой точке кода, должен был спросить самого Тейлора Отуэлла.
Но это то, что вы можете сделать:
public function register() { $this->app['player'] = $this->app->share(function($app) { return new Player(new Team\Player\Player); //// OR return new Player(new Team\Player\Active); }); $this->app->booting(function() { $loader = \Illuminate\Foundation\AliasLoader::getInstance(); $loader->alias('Player', 'Team\Player\Facades\Player'); }); }
Вашему классу Player необходимо будет реализовать StatusPlayerInterface:
class Player implements StatusPlayerInterface { }
Но я не уверен, что это так, так что, посмотрите, это предложения, я не знаю, что вы делаете именно с вашим пакетом, поэтому я просто указываю, что я вижу неправильно, Хорошо?
РЕДАКТИРОВАТЬ
Например, вы создаете свой класс Player, уже передающий статус игрока, не так ли? Но как бы вы поменяли разные статусы, если конструктор, как вы строите, получит только тот, который вы передаете через ServiceProvider? В этом случае контейнер IoC вам не поможет, потому что вы должны иметь возможность создать экземпляр этого класса с 3 статусами: активными, удаленными и ранеными.
Вы можете создать метод setPlayerStatus()
, чтобы изменить его во время запроса, конечно, но, как я надеюсь, вы можете видеть, прежде чем строить весь пакет, вы должны сначала много подумать о своей архитектуре, а затем написать свой код основываясь на этом, всегда помня, что контейнер IoC имеет свои границы, и есть некоторые разрешения, которые он не решит, просто потому, что они являются проблемами в вашей архитектуре.
EDIT 2
Вы действительно не передаете интерфейс конструктору. Вы передаете конкретный объект конкретного класса, который реализовал этот интерфейс.
Посмотрите на ошибку снова, она говорит 3 важных вещи
Argument 1 passed to Team\Player\Player::__construct() must be an instance of Team\Player\StatusPlayerInterface, none given
Поэтому вам нужно создать экземпляр Player
return new Player;
с чем-то:
return new Player(new Active);
Это все, что вам нужно, чтобы заставить его работать. Ошибка исчезнет. Но вам тоже нужен этот пакет, и я боюсь, этого недостаточно.
Как я уже говорил, если IoC может работать здесь, как вы могли бы заставить его отправить правильную реализацию Active, Retired или Injured, в то время, когда вам нужно? Я вижу два варианта:
1) Вызов
$this->app->bind('Team\Player\StatusPlayerInterface','Team\Player\Active'); $this->app->bind('Team\Player\StatusPlayerInterface','Team\Player\Retired'); $this->app->bind('Team\Player\StatusPlayerInterface','Team\Player\Injured');
каждый раз, когда вам нужен один из них, что плохо.
2) Измените архитектуру, чтобы держать вас в SOLID-треке, в случае Открытого закрытого принципа.
Взгляните на шаблон Factory Design, это может помочь вам с этой архитектурой. Это ответ на этот вопрос: что такое шаблон Factory Design в PHP? ,