【问题标题】:Yii2 dynamically loading class from nameYii2 从名称动态加载类
【发布时间】:2017-02-17 06:33:53
【问题描述】:

我在这个问题上挣扎了一段时间 - 原因可能是微不足道的。

背景

我为我的 Yii2 应用程序创建了解析器模块,这样我就可以从其他地方(移动应用程序等)调用它来从各种网站获取数据。可能有很多解析器类,都实现了相同的接口。

项目结构

...
/modules
    \_ parser
        \_components
            \_parsers
                \_SampleParser.php
        \_controllers
            \_DefaultController.php
        \_Parser.php
...
 

为了更好的可读性,我删除了一些代码。

DefaultController.php:

namespace app\modules\parser\controllers;

use Yii;
use yii\web\Controller;
use app\modules\parser\components\parsers;
use app\modules\parser\components\parsers\SampleParser;

/**
 * Default controller for the `parser` module
 */
class DefaultController extends Controller
{
    
    private function loadParser($parserName){
        
        return new SampleParser();  // if I leave this here, everything works okay
        $className = $parserName.'Parser';
        $object = new $className();
        if ($object instanceof IParseProvider){
            return $object;
        }
    }
    
...
     public function actionIndex()
    {
        $url = "http://google.com";
        $parser = 'Sample';
        $loadedParser = $this->loadParser($parser);
        $response = $loadedParser->parse($url); 
                
            
        \Yii::$app->response->format = 'json';
        return $response->toJson();
    }
...

SampleParser.php:

<?php
namespace app\modules\parser\components\parsers;

use app\modules\parser\models\IParseProvider;

class SampleParser implements IParseProvider {
    
    public function canParse($url){
        
    }
    
    public function parse($url){
        
    }
}

现在一切正常,所以我想我正在导入正确的命名空间。但是当我删除 return new SampleParser(); 并让对象由字符串名称创建时,它会失败并出现错误:

PHP 致命错误 – yii\base\ErrorException

找不到类“SampleParser”

高亮行:

$object = new $className();

我在这里做错了什么?谢谢!

【问题讨论】:

    标签: php yii2


    【解决方案1】:

    在 Yii 的帮助下再试一次:

    private function loadParser($parserName)
    {
        return \yii\di\Instance::ensure(
            'app\modules\parser\components\parsers\\' . $parserName . 'Parser',
            IParseProvider::class
        );
    }
    

    请记住,当传递的引用不是您期望的类型时,ensure() 会抛出 \yii\base\InvalidConfigException,因此您需要在某个时候捕获它。

    如果您使用的是 PHP IParseProvider::class,您可以使用完整的类名及其命名空间。

    附:删除 use app\modules\parser\components\parsers; 除非你有你想使用的名为 parsers 的类。

    【讨论】:

    • 谢谢,我已经删除了不必要的使用。顺便说一句,您的方法引发了Call to undefined method app\modules\parser\models\IParseProvider::className() - 这是正确的,这只是纯界面。当我在接口和SampleParser 中都包含静态className() 方法时,我得到Cannot call abstract method app\modules\parser\models\IParseProvider::className()
    • 哦,对不起,我忘记了你的类没有扩展 yii\base\Object - 如果你使用 PHP >=5.5,你可以使用 IParseProvider::class
    • 有效! IParseProvider::class 而不是 IParseProvider::className() 完成了这项工作。非常感谢:)请将此信息添加到您的答案中,以便我接受。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-20
    • 1970-01-01
    • 2010-12-06
    • 2011-07-23
    • 1970-01-01
    • 2018-01-15
    相关资源
    最近更新 更多