我一直致力于从程序转换 - > oop几个月了。我决定避免跳进框架。我不想依赖幕后魔术,所以在业余时间我决定转换旧项目并构建一个小框架来运行它。对于教程,我主要转向google laravel / laracast教程,因为它是最容易找到的信息。我会说我正处于我的框架和#39;是一个较小的简化(通过这个我的意思不是功能包装/复杂)版本的laravel。我还没有围绕symfony / laravel提供的所有东西,但随着我的进步,事情开始变得咔哒咔哒。目前,我相信一旦我完成旧项目的转换,我将与laravel合作。
好的,现在。我不断怀疑的一件事是依赖注入。我发现所有/大多数注射器通过构造使用类型提示注入。我开始使用静态注册表并慢慢迭代,直到我有以下类
<?php
/**
*------------------------------------------------------------------------------
*
* Framework Container - Class Builder + Injector + Container
*
* The Container Is Responsible For Dependency Injection Via Class Constructors
* Through Abstract 'Alias' Keys Defined Within The Class. It Is Also Used To
* Hold Various Data Including Closures, Or Cached Object Instances.
*
*/
namespace eSportspCMS;
use \eSportspCMS\Helpers\Support\Base;
use \eSportspCMS\Contracts\Container as ContainerContract;
class Container extends Base implements ContainerContract {
/**
* Alias Container
* Contains Alias Keys Defining Classes To Instantiate See $this->make()
*/
private $aliases = [];
/**
* Binding Container
* Contains Custom Closure Bindings See $this->make()
*/
private $bindings = [];
/**
* Cache Container
* Contains Previously Instantiated Classes See $this->make()
*/
private $cache = [];
/**
* Closure Container
* Contains Custom Closures To Avoid Hardcoding Within Class
*/
private $closures = [];
/**
* Class Dependency Key
* Public Var Within Classes Defining The Dependency List
*/
private $varkey = 'dependencies';
/**
* Define Class Dependency Key
*
* @param string $varkey Class Dependency Key
*/
public function setvarkey($varkey) {
$this->varkey = $varkey;
}
/**
* Set Data Within Containers
*
* @param string $key Key To Use When Setting Container Var
* @param mixed $value Value To Use When Setting Container Var
*/
public function alias($key, $value) { $this->aliases[$key] = $value; }
public function bind ($key, $value) { $this->bindings[$key] = $value; }
public function cache($key, $value) { $this->cache[$key] = $value; }
/**
* Add New Closure Within Container
*
* @param string $key Closure Key
* @param callable $value Callable Function
*/
public function closure($key, callable $value) {
if (method_exists($this, $key)) {
throw new \Exception($key . ' Already Exists As A Method. Which
Means This Closure Would Not Be Accessible If Set!');
}
$this->closures[$key] = $value;
}
/**
* Access Closure If Method Being Called Does Not Exist
*
* @param string $key Closure Key
* @param array $params Params To Pass To Closure
* @return mixed Closure Response If Exists
*/
public function __call($key, $params = []) {
if (isset($this->closures[$key]) && is_callable($this->closures[$key])) {
return call_user_func_array($this->closures[$key], $params);
}
return false;
}
/**
* Create New Class Instance
*
* Forces $this->make() To Instantiate A New Class Instead Of Returning
* A Cached Instance.
*
* @see $this->make() Comments
*/
public function makeNew($class, $params = []) {
return $this->make($class, $params, false, true);
}
/**
* Pull Class From Cache Based On Key, Call Binding Or Instantiate Class
* Resolve Dependencies And Pass Via Construct.
*
* @param string $key Alias Key | Binding Key | Class To Make
* @param array $params Additional Params Passed Via Constructor
* @param bool $cache Determines If Class Can Be Cached
* @param bool $new Forces New Instance Of Object
* @return object Instantiated Or Cached Object
*/
public function make($key, $params = [], $cache = true, $new = false) {
/**
* Params Indicate Cached Instance Can Be Used
*/
if (!$new && isset($this->cache[$key])) {
return $this->cache[$key];
}
/**
* If Binding Is Defined And Key Matches Return It Instead Of Building
* The Class Directly. Replace Params With App
*/
if (isset($this->bindings[$key]) && is_callable($this->bindings[$key])) {
$instance = call_user_func_array($this->bindings[$key], $this->make('app'));
$cache ? $this->cache($key, $instance) : '';
return $instance;
}
/**
* Cache And Binding Statement Failed! Attempt To Build Class.
*
* If Class Exists Instantiate, Resolve/Pass Dependencies,
* Cache ( If Allowed ), And Return.
*
* Else Throw Exception!
*/
$classname = isset($this->aliases[$key]) ? $this->aliases[$key] : $key;
if (class_exists($classname)) {
$instance = new $classname($this->resolveDependencies($classname, $params));
$cache ? $this->cache($key, $instance) : '';
return $instance;
}
// All Statements Failed! Class Couldn't Be Created
throw new \Exception('Container Could Not Create Class: ' . $classname);
}
/**
* Resolve/Build Class Dependencies
*
* Dependencies Cascade To Simplify/Unify Dependency Setting Within Grouped
* Classes. ( Classes Like Controllers Which Would Extend Base Controller )
*
* @param string $classname Class Being Instantiated
* @param array $params Additional Params Being Passed
* @return array Assoc Array With Class Dependencies
*/
private function resolveDependencies($classname, $params = []) {
// Define Class Tree
$classes = array_reverse((array) class_parents($classname));
$classes[] = $classname;
// Retrieve Class Dependencies From Tree ( Alias Keys ) & Build
$dependencies = $this->dependencies($classes);
foreach ((array) $dependencies as $dependency) {
$dependencies[$dependency] = $this->make($dependency);
}
// Return Merged Dependencies
return array_merge($dependencies, $params);
}
/**
* Retrieve Class Dependency List ( Alias Keys )
*
* @param array $classes Array Containing Classes
* @return array Class Dependencies ( Alias Keys )
*/
private function dependencies($classes = []) {
if (!$classes) { return; }
$aliases = [];
foreach ((array) $classes as $c) {
$vars = get_class_vars($c);
if (isset($vars[$this->varkey])) {
$aliases = array_merge($aliases, $vars[$this->varkey]);
}
}
return array_unique($aliases);
}
}
我如何使用 框架应用程序类将扩展容器。在应用程序引导期间,将加载依赖项的别名键(我使用laravel的相同配置设置 - 从config目录中的返回数组加载配置)当使用容器实例化类时,它将搜索依赖项列表&#39; varkey& #39;,它将迭代并合并父类依赖关系(对于分组依赖关系,如模型 - 模型扩展基础模型),然后它将构建依赖关系树,实例化类和缓存(如果允许)。依赖关系通过构造作为assoc数组传递给类[&#39;别名&#39; =&GT;宾语]。扩展&#39; \ helpers \ support \ base&#39;的类class具有为它们设置的依赖项。基础构造类使用别名键作为类键遍历数组,设置类中的依赖关系。
关注 当看到其他注射器时,我看到使用了类型,我不确定这是否是由于这种类型的依赖注入的缺陷,我还没有看到。我认为别名键的方式是&#39;接口&#39;最重要的是,所使用的依赖项实现了契约,所以当我改变类时,契约仍然定义了类的要求。
问题 有理由: *偏离使用这个注射器?为什么? (我不是在寻找&#34;不要重新发明轮子&#34;答案我想要进一步了解我并了解我在做什么) *实施服务提供商&#34; laravel教程&#34;什么时候用?目前我操纵构造中的依赖项(如果我需要来自依赖项的特定数据,我使用getters / setters来检索数据并在类中设置)
我是否需要为我创建的每个类(包括控制器)创建一个契约/接口,或者是仅在依赖项的类上使用的接口? (我发现了很多混合的反馈,所以我被撕裂了,以为我会把它扔进去)
类示例 以下类是我的404错误控制器。它是其他控制器中使用的依赖项之一,因为我有依赖于db数据(用户)的页面,如果用户不存在,我会显示404错误。
<?php
/**
*------------------------------------------------------------------------------
*
* Error Controller
*
*/
namespace Application\Controllers;
use \eSportspCMS\Helpers\Support\Base;
class Error extends Base {
public $dependencies = ['http', 'log', 'metadata', 'view'];
/**
* 404 Error Page Not Found
*/
public function display404($msg = '', $params = []) {
// If Msg Present Log Error
!$msg ?: $this->log->error($msg, $params);
// Define 404 HTTP Header
$this->http->set('header', 'HTTP/1.1 404 Not Found');
// Set 404 Sitetitle
$this->metadata->sitetitle('error', 'display404');
// Return View File + View Data
return $this->view->display('www/custompages', $this->custompage->info(1));
}
}
提前感谢您提供所有反馈。