Search code examples
phplinuxyii2

How to include Class when running php file (Yii 2) in terminal


I want to execute this code form the terminal on Linux and it seems my file is not finding the needed model

This is the function i want to run

use backend\models\Invoice;

function myTest(){
    $model = Invoice::find()->where(['status' => Invoice::STATUS_UNPAID])->all();
    
    if($model){
        foreach ($model as $value) {
            Invoice::payInvoice($value->id);
        }
        
    }
}

myTest();

On terminal i run this

# php -f /var/www/html/checkstall.test/checkstall.com/common/cronjob/test.php

Below is the output i got

PHP Fatal error:  Uncaught Error: Class "backend\models\Invoice" not found in /var/www/html/checkstall.test/checkstall.com/common/cronjob/test.php:6
Stack trace:
#0 /var/www/html/checkstall.test/checkstall.com/common/cronjob/test.php(16): myTest()
#1 {main}
  thrown in /var/www/html/checkstall.test/checkstall.com/common/cronjob/test.php on line 6

And i'm so sure \backend\models\Invoice is present because i can run this code form within my project without any Error. I think this has to do with how Yii uses and include files in terminal or so.


Solution

  • Your confusion here is that the use statement in PHP has nothing to do with loading code. Instead, it is part of the feature for Namespaces: a way to have long unambiguous names for your classes and functions, without having to type the whole name each time.

    Specifically, use backend\models\Invoice; means "in this file, when I write Invoice as a class name, act as though I wrote \backend\models\Invoice instead". It's a simple text substitution by the compiler (i.e. the first piece of the PHP engine that looks at your code, before it attempts to run any of it).

    To load a file, you need to use one of include, include_once, require, or require_once. These run all the PHP code in a file, including any class definitions.

    The reason you don't normally have to do this manually is that PHP has another feature called autoloading - when PHP finds a class name that's not defined, it triggers a function you registered earlier, and that function can do what's needed to define the class. Normally, that autoloader will include/require the right file; and often, that whole thing is defined as part of a framework or tool, so all you have to do is put the file in the right place, and it appears to work "by magic".

    Just to join the dots fully, writing use backend\models\Invoice; will not on its own cause the autoloader to run - at this point, PHP doesn't need a class with that name, it's just doing some find-and-replace in the rest of the file. It's when you actually do something with the class that the autoloader would run - i.e. when it tries to execute the line Invoice::find(), which the compiler has expanded as though you wrote \backend\models\Invoice::find()

    What you most likely need to do in your command-line script is manually include some initial "bootstrap" or "startup" file which tells PHP what autoloading function to use. Your example also shows you fetching some data from somewhere, so presumably that file will also need to load configuration to connect to a database of some sort. Since you're using a framework, there may be a specific recommended structure for writing command-line scripts which makes sure everything is set up for you, and gives you some appropriate helpers.