好的,在访问一个类中的其他几个类时,我经常遇到一些未解决的错误。
根据首先需要哪个类,它不会在其他文件的 __ construct 函数中访问。
Undefined property: Container::$Core in /usr/share/nginx/html/app/classes/class.users.php on line 9
的 class.container.php
public function __construct() {
if(isset(self::$class)) {
foreach(self::$class as $key => $value) {
if(!isset($this->{$key})) {
$this->{$key} = $value;
}
}
}
}
public function setClassHandlers($class = []) {
if(!isset(self::$class)) {
foreach($class as $name => $file) {
$file = DIR . "app/classes/" . $file;
if(!isset(self::$library[$name])) {
// Get interface file
$interface = DIR . "app/classes/interfaces/interface.".strtolower($name).".php";
// Check if interface file exists
if(!file_exists($interface)) {
// Throw exception
$this->throwException("Unable to load interface file: {$interface}");
}
// Require interface
require_once $interface;
//Check if interface is set
if(!interface_exists("i".ucfirst($name))) {
// Throw exception
$this->throwException("Unable to find interface: {$interface}");
}
// Check if class file exists
if(!file_exists($file)) {
// Throw exception
$this->throwException("Unable to load class file: {$file}");
}
// Require class
require_once $file;
// Check if class file exists
if(class_exists($name)) {
// Set Library
self::$library[$name] = $file;
// Set interface
self::$interface[$name] = $interface;
// Set class // class.container.php
self::$class[$name] = new $name(new self);
$this->{$name} = self::$class[$name];
} else {
// Thror error
$this->throwException("Unable to load class: {$name}", self::$library[$name]);
}
}
}
}
}
在 index.php :
中的函数中插入参数require_once DIR . 'app/management/dependency.php';
$container = new Container();
$container->setClassHandlers([
// Name // Path
'Database' => 'class.database.php',
'Config' => 'class.config.php',
'Users' => 'class.users.php',
'Core' => 'class.core.php',
//'Admin' => 'class.admin.php',
//'Forum' => 'class.forum.php',
//'Template' => 'class.template.php'
]);
class.users.php
public function __construct(Container $class) {
$this->db = $class->Database;
$this->core = $class->Core;
$this->ip = $this->core->userIP();
$this->container = $class;
}
例如,用户和核心在彼此的同一文件中使用,但如上所述,如果首先需要核心, 用户不是该类中的可用依赖项 我真的不太确定如何解决这个问题,所以每一个帮助都表示赞赏。
答案 0 :(得分:1)
您的"容器"正在尝试在运行setClassHandlers方法时实例化包含的对象,到那时并非所有属性都可以设置。
另外,你的容器不是"懒惰"足够。正试图实例化所有现在,即使可能不需要它。
尝试以下
首先,删除以下行:
// Set class // class.container.php
self::$class[$name] = new $name(new self);
$this->{$name} = self::$class[$name];
然后,向Container类添加私有数组服务:
private $services = [];
最后,在容器中添加一个魔法吸气剂:
function __get($service)
{
if ( ! isset($this->services[$service]) ) {
$this->services[$service] = new $service();
}
return $this->services[$service];
}
再一次,了解这一点很棒,但我建议你看看其他一些实现,以便从中学习。 Pimple很棒,很简单,也很容易理解。
这里我们在所有对象上注入容器而不是对象具体依赖项,这通常(正确地)不受欢迎。但我不想对您的设计进行更多修改,您最好自己学习。
最重要的是,你的容器还处理autoloader更好处理的事情,以及混合责任。
另外,正如我在评论中所说,你正在重新发明PHP中已存在的__DIR__
常量。您正在使用
define( 'DIR', dirname(__FILE__) . '/' );
几乎等同于__DIR__
(或者更准确地说,等同于__DIR__ . '/'
)。
最后,您的大多数麻烦都是由循环依赖引起的,您的容器(也不是任何容器)无法修复。 A依赖于B,它依赖于A.唯一可以解决的方法是使用setter来注入依赖项。
更简单的实现,或多或少地遵循您的代码:
自动加载:
function autoload_so($class)
{
$file = __DIR__ . "/app/classes/class." . strtolower($class) . '.php';
if (file_exists($file)) {
include_once($file);
return true;
}
return false;
}
spl_autoload_register('autoload_so');
我没有使用名称空间,我忽略了你的界面逻辑。这也有点奇怪。您需要为接口实现自己的加载,您应该能够这样做。
对于容器:
class MyContainer
{
public $services = [];
function __get($service)
{
if ( ! isset($this->services[$service]) ) {
$this->services[$service] = call_user_func([$this, "get_$service"]);
}
return $this->services[$service];
}
/**
* @return Users
*/
private function get_Users()
{
return new Users($this->Database, $this->Core);
}
/**
* @return Core
*/
private function get_Core()
{
return new Core();
}
/**
* @return Database
*/
private function get_Database()
{
return new Database($this->Core);
}
}
请注意
最后你的课程会是这样的:
数据库
<?php
class Database
{
public function __construct(Core $core)
{
$this->core = $core;
}
}
用户
class Users
{
public $ip;
public function __construct(Database $db, Core $core)
{
$this->db = $db;
$this->core = $core;
$this->ip = $this->core->userIP();
}
}
等。
同样,这一切都非常粗糙。我会使用名称空间和更通用的自动加载器和目录结构。
所有这一切都应该足以让你建立自己的起点。
但是没有容器会神奇地修复你的循环依赖。