2

I struggle with this problem for a while - and the reason is probably trivial.

Background

I've created parser module for my Yii2 application so I can call it from other places (mobile app, etc.) to get data from various websites. There may be many parser classes, all implementing same interface.

Project structure

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

I've removed some code for better readability.

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){
        
    }
}

Right now everything works more or less ok, so I guess I'm importing correct namespaces. But when I remove return new SampleParser(); and let the object to be created by string name, it fails with error:

PHP Fatal Error – yii\base\ErrorException

Class 'SampleParser' not found

with highlighted line:

$object = new $className();

What am I doing wrong here? Thanks!

1 Answer 1

3

Try again with help of Yii:

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

Remember that ensure() throws \yii\base\InvalidConfigException when passed reference is not of the type you expect so you need to catch it at some point.

If you are using PHP < 5.5 instead of IParseProvider::class you can use full class name with it's namespace.

P.S. remove use app\modules\parser\components\parsers; unless you have got class named parsers you want to use.

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks, I've removed unnecessary using. BTW your method raises Call to undefined method app\modules\parser\models\IParseProvider::className() - and thats correct, that's just pure interface. When I include static className() method in both interface and SampleParser, I get Cannot call abstract method app\modules\parser\models\IParseProvider::className().
Oh, sorry, I forgot your class does not extend yii\base\Object - you can use IParseProvider::class if you are using PHP >=5.5
It works! IParseProvider::class instead of IParseProvider::className() did the job. Thank you very much :) Please add this information to your answer so I can accept it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.