How to make sure the correct class file is loaded when calling / extending class

后端 未结 2 1536
时光取名叫无心
时光取名叫无心 2021-01-27 11:31

I did brows through that question page but the answers given, I felt, didn\'t sufficiently answer the question I was struggling with.

I have a little php project. In this

相关标签:
2条回答
  • 2021-01-27 12:17

    Remove the line

    include('./Class1.php');
    
    0 讨论(0)
  • 2021-01-27 12:24

    Quick Answer

    Unless you've specified the full path to the include file, PHP will always try to resolve files according to the location of the entry script. In your case, your entry script seems to be app.php at the root of the application.

    So in your Class2.php, instead of include('./Class1.php');, you should write include('Models/Class1.php'); and things should work. But while it fix a short term problem, your code would be really non-portable. Besides, including the same file twice would result in another error (e.g. re-declaring class).

    Slightly Smarter Approach

    A slightly smarter would be to do this in Class2.php instead.

    <?php
    // Class2.php
    
    namespace Models\Class2;
    
    use \Models\Class1\Class1;
    
    include_once __DIR__ . '/Class2.php';
    
    /**
     * Class2 does other things
     */
    class Class2 extends Class1 {
      public function someMethod() {
        // code
      }
    }
    
    

    The variable __DIR__ will always be resolved to the directory of the script file, not the entry script.

    But again, it is clumsy and error prone to do file includes by hand.

    An Even Smarter Approach: Autoload

    PHP supports file autoloading when a class is declare. That is to have a piece of code to do the file include when a class is called. If you want to have fun, you're welcome to write your own autoloader function and register to spl_autoload_register. With a combination of the __DIR__ technique we talked about, you can easily resolve the autoloading path from namespace.

    A quick and ugly autoloading app.php would probably look like this:

    <?php
    // app.php
    
    use Models\Class1\Class1;
    use Models\Class2\Class2;
    
    spl_autoload_register(function ($class_name) {
            $realClassName = basename(str_replace('\\', DIRECTORY_SEPARATOR, $class_name));
            include_once __DIR__ . DIRECTORY_SEPARATOR . 'Models' . DIRECTORY_SEPARATOR . $realClassName . '.php';
    });
    
    $c1 = new Class1();
    $c2 = new Class2();
    
    

    The Smart Approach: Composer Autoload

    If you're learning OOP PHP today, I'd highly recommend you to learn Composer and PSR-4. PSR-4 defines how you should structure a PHP application for class autoloading. Composer implements a PSR-4 autoloader by default.

    First you should comply with the namespace standard. The least change to do is to loose the extra "Class1" and "Class2" in your namespace:

    <?php
    // Class1.php
    
    namespace Models;
    
    /**
     * Class1 does things
     */
    class Class1 {
      public function someMethod() {
        // code
      }
    }
    
    
    <?php
    // Class2.php
    
    namespace Models;
    
    use \Models\Class1;
    
    
    /**
     * Class2 does other things
     */
    class Class2 extends Class1 {
      public function someMethod() {
        // code
      }
    }
    
    

    With a nicely structured application folder, namespace structure and a correctly written autoload.psr-4 section in composer.json, composer will help you to generate a class autoloader. Your composer.json would probably look like this:

    {
        "autoload": {
            "psr-4": {
                "Model\\": "Model/"
            }
        }
    }
    

    You may now run composer dump-autoload to create the autoloader. Then you can simply add this to your entry script app.php. When things are ready, you may simply add use and new statement anywhere in the application.:

    <?php
    // app.php
    
    use Models\Class1;
    use Models\Class2;
    
    require_once './vendor/autoload.php';
    
    $c1 = new Class1();
    $c2 = new Class2();
    
    

    All includes are handled by the autoloader. Hands free.

    0 讨论(0)
提交回复
热议问题