我创建了这个工厂类:
namespace ValidatorFactory;
foreach (glob("Types/*.php") as $filename)
{
include $filename;
}
class ValidatorFactory
{
public static function getValidator($betTypeId)
{
switch ($betTypeId)
{
case 1:
return new B();
break;
default:
return null;
}
}
}
这是我的一个抽象类定义:
abstract class A
{
abstract function validateSchema($schema);
}
这是我的B类定义:
class B extends A
{
function validateSchema($schema)
{
return true;
}
}
现在我想在我的项目中的其他文件中使用工厂类,这是我的工作方式:
$obj = ValidatorFactory::getValidator($someId);
我正在使用Laravel并通过作曲家(和this tutorial)我尝试加载ValidatorFactory
类,就像内置的laravel类一样。这是我添加到作曲家文件中的内容:
"autoload": {
"classmap": [
...
],
"psr-0": {
"ValidatorFactory": "app/"
}
},
我已经composer update
了。
我的问题是我的ValidatorFactory未加载,因为我收到此错误:
Class 'ValidatorFactory' not found
如果我要添加这样的命名空间:
$obj = ValidatorFactory\ValidatorFactory::getValidator($someId);
我收到其他错误,现在是:
Class 'ValidatorFactory\B' not found
所以有2个问题,首先与larave / composer autoload(名称空间)有关。第二个与php中的包含和继承(我怀疑)有关。
如何解决这两个问题?谢谢!
更新 正如答案中所建议的,我为所有3个涉及的类A,B和工厂添加了相同的命名空间。没有班级,包括任何其他班级。
在调用工厂getValidator
函数的类中,我这样做:
$obj = ValidatorFactory\ValidatorFactory::getValidator($someId);
仍然得到B级未知的错误:(
以下是更新后的B类的样子:
namespace ValidatorFactory;
class B extends A
{
function validateSchema($schema)
{
return true;
}
}
文件结构如下所示:工厂文件位于app/dir1/
,A类和B类位于app/dir1/dir2/
答案 0 :(得分:2)
include
中定义的任何内容都在global namespace中定义,因此抽象类定义分别定义\A
和\B
类(并且不< / em> ValidatorFactory\A
或ValidatorFactory\B
)。为了按照您的方式使用它们,您需要在包含它们之后为每个语句添加use
语句。
但为什么要包括任何东西呢?这又是一个自动加载器的想法。如果你想声明一个类,把它放在你的一个命名空间中,让Laravel和composer为你努力工作。
<强>更新强>
return new B();
尝试将该行更改为:
return new \B();
这将清除你的第二个错误。至于第一个,您声明您的Validator工厂存在于命名空间中:
namespace ValidatorFactory;
使用该类(在同一名称空间中不)的任何代码都需要A)使用use
语句导入该类,或者B)在引用它时使用完全限定名称空间:
use ValidatorFactory\ValidatorFactory;
// ...
$factory = new ValidatorFactory();
或强>
$factory = new ValidatorFactory\ValidatorFactory();
请记住,所有命名空间都是为了让您和另一位开发人员为一个类命名完全相同的东西。例如,也许我正在研究某种路线映射工具。我可能想要定义一个Route
类,因为该名称非常适合我当前的问题域。然而,泰勒已经击败了我,因为已经有Route
级。使用名称 空间我可以确保无论我想要什么,我仍然可以命名我想要的任何东西,并且不会与已经存在的东西发生冲突已命名或尚未命名的东西。
更新2
使用composer的项目中的命名空间需要镜像底层文件所在的目录路径(这就是自动加载器可以找到它们的方式 - 它基本上查看了命名空间和类名,并将其转换为文件的目录路径,并附加.php
扩展名。如果你有这样的课程:
// File: app/dir1/dir2/A.php
class A{}
// File: app/dir1/dir3/B.php
class B{}
然后A必须位于命名空间dir1\dir2
中,其完全限定名称为dir1\dir2\A
。同样,B类必须位于名称空间dir1\dir3
中,其完全限定名称为dir1\dir3\B
。
答案 1 :(得分:1)
从我们的chat discussion,我们无法弄清楚为什么PSR-0不适合你。事实证明PSR-4配置工作正常。所以我在这里总结一下我们在讨论中使用PSR-4自动加载的方法。
文件结构:
app |- commands |- config |- ... |- MyValidator |- MyValidatorFactory.php |- A.php |- B.php |- ...
<强> MyValidatorFactory.php 强>
namespace MyValidator;
class MyValidatorFactory
{
...
return new B();
...
}
<强> B.php 强>
namespace MyValidator;
class B extends A
{
function validateSchema($schema)
{
return true;
}
}
最后,您可以在 composer.json 中设置PSR-4自动加载:
"autoload": {
...
"psr-4": {
"MyValidator\\": "app/MyValidator"
}
}
加分点:
使用上面的psr-4配置,您还可以构建名称空间和类,如下所示:
app |- commands |- config |- ... |- MyApp |- Validators |- MyValidatorFactory.php |- A.php |- B.php |- ...
并将psr-4配置设置为"MyApp\\": "app/MyApp"
,自动加载器将识别您的类并使用它如下所示:
new \MyApp\Validators\MyValidatorFactory;
new \MyApp\Validators\A;
new \MyApp\Validators\B;