Php 从类名创建对象在命名空间内不起作用

Php 从类名创建对象在命名空间内不起作用,php,oop,laravel,Php,Oop,Laravel,我正在我的项目中创建一个factory类,该类以字符串形式获取报告类型。此字符串具有实现报表接口的具体类的名称 我遇到的问题是,当我实例化这个类时,我得到一个类未找到错误 以下是工厂代码 namespace App\Term\Reports; class Factory { public static function build($type) { $obj = new CableBySensor(); // Works! // $type

我正在我的项目中创建一个factory类,该类以字符串形式获取报告类型。此字符串具有实现报表接口的具体类的名称

我遇到的问题是,当我实例化这个类时,我得到一个
类未找到
错误

以下是工厂代码

namespace App\Term\Reports;

class Factory
{
    public static function build($type)
    {
        $obj = new CableBySensor();  // Works!

        // $type == 'CableBySensor'
        $obj2 = new $type;         // Class not found :(

        // ... validates if the class exists ...
        // ... and if it implements the Report Interface ...
        // ... throw exception if class doesn't exist or doesn't implements interface
        // ... then returns the corresponding object.
    }
}
这两种方法实际上是一样的

首先:为什么必须在字符串中指定类的完整限定名才能使其工作?类
CableBySensor
Factory
位于同一命名空间中

这开始给我带来麻烦,因为我还想验证被实例化的类是否实现了一个
ReportsInterface

第二:我如何克服这个问题?我应该这样调用工厂吗?
$myReport=factory::build('App\Term\Reports\。$className)
或者我应该在工厂类中使用
\uu名称空间\uu
常量,例如:
$obj=new\uu名称空间\uuu.'\'$类名


谢谢。

不管工厂方法在这里是否有用, 问题在于试图从动态变量实例化

或者正如所指出的:

必须注意,当使用动态类名[…]时,“当前名称空间”[…]是全局名称空间

可能有3种解决方案:

  • 将完全限定的类名传递给工厂方法(arghh…)

  • 或者,检查您的构建方法,并在必要时为名称空间添加前缀(如建议的那样)(对我来说听起来不是那么简单)

  • 或者,如果您有PHP5.5+为什么不使用? 就我个人而言,只要有可能,我都会选择:

    $instance = Factory::build(CableBySensor::class);
    

让我们退一步,为什么要将
$type
作为字符串传递?此外,您是否会考虑使用
开关($type){case“CableBySensor”:$obj2=new CableBySensor();break;}
。您是否尝试过使用名称空间来查看它是否有效?我建议您在线阅读有关参数化工厂模式的内容。我个人不会写一个工厂类,然后像你们一样使用它。大家好,谢谢你们的评论。我一直在关注这件事@Halcyon只是我认为每次我有一个新的报告类型时,我都必须修改工厂并在switch语句中添加一个
case
。按照我的方式,它可以与实现接口的任何类一起工作(或者我认为是D)。我将验证该类是否实现了报表接口。-@YehiaAwad使用名称空间工作@我会的,谢谢你!我不完全确定这篇文章的作者是否理解如何使用工厂。这对我来说似乎非常可怕:“工厂能够创建不同类型的对象,而不一定知道实际创建的对象是什么类型的。”。通常情况下,如果实例化对象很复杂,或者需要将不希望传递的依赖项传递给需要创建实例的对象,那么您会使用工厂(因此,您会给它一个“抽象”工厂)。回答第一个问题。大约在第二天。我同意第二种,不过稍微调整一下。尽管我很想使用第三个选项,但在这一点上,我只有一个名为
cable\u by\u sensor
(这是用户选择的选项)的字符串。因此,我将
studly_case()
应用于
$type
(然后作为惯例,我有实际的类名)。在这之后,我在前面添加
\uuuu名称空间\uuuu
,然后验证类是否实现了我想要的接口,然后返回一个新的对象实例或抛出异常的元素。
public static function build($type)
{
    if ($type[0] !== '\\') {
        $type = '\\' . __NAMESPACE__ . '\\' . $type;
    }
    $obj = new $type;
    ...
}
$instance = Factory::build(CableBySensor::class);