2017-02-17 69 views
2

我在这个问题上挣扎了一段时间 - 原因可能是微不足道的。Yii2从名称动态加载班级

背景

我创建解析器模块为我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 Fatal Error – yii\base\ErrorException

Class 'SampleParser' not found

与突出显示的行:

$object = new $className();

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

回答

2

与谊的帮助,请再试一次:

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

记住ensure()抛出\yii\base\InvalidConfigException时传递的引用是你期望,所以你必须抓住它在某些时候的类型不。

如果您使用PHP < 5.5而不是IParseProvider::class,则可以使用完整的类名称及其名称空间。

P.S.删除use app\modules\parser\components\parsers;,除非您有要使用的类名为parsers的类。

+0

谢谢,我已经删除了不必要的使用。顺便说一句,你的方法引发'调用未定义的方法app \ modules \ parser \ models \ IParseProvider :: className()' - 那是正确的,那只是纯粹的接口。当我在接口和SampleParser中都包含静态'className()'方法时,我得到'不能调用抽象方法app \ modules \ parser \ models \ IParseProvider :: className()'。 – Mark

+1

噢,对不起,我忘记了你的课程没有扩展'yii \ base \ Object' - 如果你使用的是PHP> = 5.5 – Bizley

+0

,你可以使用'IParseProvider :: class'它可行! 'IParseProvider :: class'代替'IParseProvider :: className()'完成了这项工作。非常感谢:)请将这些信息添加到您的答案,以便我可以接受它。 – Mark