Writing Bulletproof __autoload Function for PHP

I am trying to define my PHP __autoload function as bulletproof and flexible as possible.

Here is a breakdown of my application structure:

/dev (root)
    /my_app
        /php
            /classes
                - Class1.php
                - Class2.php
                - Class3.php
        /scripts
            myscript.php (the file I have to include the classes in)

This is pretty straight forward. My problem is this: how to write my __autoload function so that I can include any class I want, no matter how deep the nested calling file is in the directory structure. I know that this has something to do with the functions __FILE__, realpathand dirname, but I'm not sure that they can be combined to achieve the flexibility that I use.

Here is a quick test I did:

<?php
echo realpath(dirname(__FILE__)) . "/php/classes/Class1.php";
?>

Result:

/home/mydirectory/dev.mysite.com/my_app/php/scripts/php/classes/Class1.php

, , . , myscript.php /my _app, .

?

+3
4

$_SERVER['DOCUMENT_ROOT'] -. . , .

//set in config file
if(!isset($_SESSION['APP_DIR'])) $_SESSION['APP_DIR'] = "my_app";

//autoload
//builds a string with document root/app_name/classes
//takes the app name and replaces anything not alphanumeric or _ with an _ and
//makes it lowercase in case of case sensitive. as long as you follow this naming
//scheme for app directories it should be fine for multiple apps.
$classPath = $_SERVER['DOCUMENT_ROOT'] . '/' .
           strtolower(preg_replace('/\W+/', '_', $_SESSION['APP_DIR'])) .
           '/classes/';
+1

spl_autoload. include_path

- , , :

ini_set($your_class_dir_here .PATH_SEPERATOR. ini_get('include_path'));

, spl_autoload_register, .

, php .

<?php

namespace Red
{
    // since we don't have the Object yet as we load this file, this is the only place where this needs to be done.
    require_once 'Object.php';

    /**
     * Loader implements a rudimentary autoloader stack.
     */
    class Loader extends Object
    {
        /**
         * @var Loader 
         */
        static protected $instance = null;

        /**
         * @var string 
         */
        protected $basePath;

        /**
         * @return Loader
         */
        static public function instance()
        {
            if (self::$instance == null)
            {
                self::$instance = new self();
            }
            return self::$instance;
        }

        /**
         * Initialize the autoloader. Future expansions to the 
         * autoloader stack should be registered in here.
         */
        static public function Init()
        {
            spl_autoload_register(array(self::instance(), 'autoLoadInNamespace'));
        }

        /**
         * PHP calls this method when a class is used that has not been
         * defined yet. 
         * 
         * I'm returning a boolean for success which isn't required (php ignores it)
         * but makes life easier when the stack grows.
         * 
         * @param string $fullyQualifiedClassName
         * @return boolean 
         */
        public function autoLoadInNamespace($fullyQualifiedClassName)
        {
            $pathParts = preg_split('/\\\\/', $fullyQualifiedClassName, -1, PREG_SPLIT_NO_EMPTY);
            array_unshift($pathParts, $this->basePath);
            $pathToFile = implode(DIRECTORY_SEPARATOR, $pathParts) . '.php';

            if (file_exists($pathToFile))
            {
                require_once $pathToFile;
                return true;
            }
            return false;
        }

        /**
         * Constructor is protected because we don't want multiple instances
         * But we do want an instance to talk to later on.
         */
        protected function __construct()
        {
            $this->basePath = realpath(dirname(__FILE__) . DIRECTORY_SEPARATOR . '..');
        }
    }
}

#EOF;

Loader \Red :

<?php
// This is where the magic is prepared. 
require_once implode(DIRECTORY_SEPARATOR, array(dirname(__FILE__), 'Red', 'Loader.php'));
// Initialize the autoloader, no more require_once for every class
// and everything is OOP from here on in.
Red\Loader::Init();

#EOF
+3

. , , , , ( , ). , Name = > pathToClass.

+1

There are two ways. Or, you specify the complete absolute path to your class directory ( /home/mydirectory/dev.mysite.com/my_app/php/classes/), which I would not recommend, since it includes changing the absolute path if you change hosts. Or you can use a relative path that is simpler and portable:

require_once '../classes/'.$classname;

No need to get realpathhere, PHP is excellent with relative paths .;)

PS: realpath(dirname(__FILE__))- this is a duplicate, I think. __FILE__is already the "real path", so you do not need to call realpath.

0
source

Source: https://habr.com/ru/post/1755142/


All Articles