Asked  1 Year ago    Answers:  5   Viewed   5 times

spl_autoload_register can do this kind of job,but I don't understand how is that kind of job done?

spl_autoload_register(array('Doctrine', 'autoload'));

 Answers

4

The basic idea is that you don't have to write include/require instructions anymore : whenever you're trying to use a non-defined class, PHP will call the autoloader.

The job of the autoloader, then, is to determine which file should be loaded, and include it, so the class becomes defined.

PHP can then use that class, as if you were the one who wrote the include instruction, that has in fact been executed in the autoloading function.


The "trick" is that the autoloading function :

  • only receives the name of the class
  • has to determine which file to load -- i.e. which file contains that class.

This is the reason for naming convention, such as the PEAR one, which says that class such as Project_SubProject_Component_Name are mapped to files such as Project/SubProject/Component/Name.php -- i.e. '_' in the class names are replaces by slashes (directories, subdirectories) on the filesystem.


For instance, if you take a look at the Doctrine_Core::autoload method, which is the one that will be called as an autoloader in your case, it contains this portion of code (after dealing with some specific cases) :

$class = self::getPath() 
            . DIRECTORY_SEPARATOR . 
            str_replace('_', DIRECTORY_SEPARATOR, $className) 
            . '.php';
if (file_exists($class)) {
    require $class;
    return true;
}
return false;

Which means the class name's is mapped to the filesystem, replacing '_' by '/', and adding a final .php to the file name.

For instance, if you're trying to use the Doctrine_Query_Filter_Chain class, and it is not known by PHP, the Doctrine_Core::autoload function will be called ; it'll determine that the file that should be loaded is Doctrine/Query/Filter/Chain.php ; and as that file exists, it'll be included -- which means PHP now "knows" the Doctrine_Query_Filter_Chain class.

Saturday, May 29, 2021
 
ojrac
 
2

The problem would also be that if you declared a function foo() and a method foo(), php would have a hard time figuring out which you meant - consider this example:

<?php
function foo()
{
    echo 'blah';
}

class bar
{
    function foo()
    {
         echo 'bleh';
    }
    function bar()
    {
         // Here, foo() would be ambigious if $this-> wasn't needed.
    }
}
?>

So basically you can say that PHP - because of its "non-100%-object-orientedness" (meaning that you can also have functions outside classes) - has this "feature" :)

Thursday, April 1, 2021
 
MGP
 
MGP
3
        $datefrom = strtotime($datefrom, 0);
        $dateto = strtotime($dateto, 0);

        $difference = $dateto - $datefrom;

        $days_difference = floor($difference / 86400);
        $weeks_difference = floor($days_difference / 7); // Complete weeks

        $first_day = date("w", $datefrom);
        $days_remainder = floor($days_difference % 7);

        $odd_days = $first_day + $days_remainder; // Do we have a Saturday or Sunday in the remainder?
        if ($odd_days > 7) { // Sunday
            $days_remainder--;
        }
        if ($odd_days > 6) { // Saturday
            $days_remainder--;
        }

        $datediff = ($weeks_difference * 5) + $days_remainder;

From here: http://www.addedbytes.com/php/php-datediff-function/

Thursday, April 1, 2021
 
elias
 
5

For the purpose of keeping individuals who may come across this answer from obtaining out-of-date information I have updated it in regards to the latest PSR autoloading standards. The original answer has been maintained for historical purposes and for those who are only interested in the PSR-0 autoloader.

Updated Answer

The PHP-FIG has officially deprecated the PSR-0 standard in favor of the alternative autoloader, PSR-4. Although the two are similar in some aspects they are also very different in others. (E.g.: the handling of underscores in class names.)

You may be thinking to yourself -- "I use PSR-0 now and it works fine." The truth of the matter is that PSR-0 will still work fine for certain projects. This is especially true when backwards compatibility with a package that doesn't use namespaces is concerned. PSR-0 is still a decent autoloading principle, but it has its own shortcomings.

Of course, if there is one thing that is a constant with programming, it is that code eventually changes and programming techniques continue to evolve. You can do yourself a favor today by preparing yourself for tomorrow. Therefore, if you are just starting a project or are trying to port a project to a newer version of PHP that can use namespaces, you should seriously consider using the PSR-4 autoloader.

It is also worth noting that if you are developing a project that does not use namespaces then PSR-4 does not apply to you. In this case PSR-0 or your own custom autoloader applies.


Original Answer

If you want to go with namespaces in your classes, then the PSR-0 route is a pretty good way to autoload. Basically your namespace represents you directory structure and classes can be loaded based on a convention.

If the PSR-0 method doesn't meet all your needs (or doesn't play nice with existing code) you can still add more functions with spl_autoload_register and PHP will go through them one by one in an attempt to load classes.

Example usage:

First thing is first, if you aren't familiar with namespaces in PHP then you will benefit from checking out the PHP manual on the subject. They can be a bit confusing at first, but their benefits are worth the initial confusion.

So I said that PSR-0 works by associating your namespaces with your directory structure. Let's use your directories for an example. You have in your root folder (wherever it may be) the following:

Project directory:  <- Let's call this directory "MyProject"
    Controllers:
       Main.php
       File.php
       About.php
    Libs:
       Main.php
       Front_controller.php
    Models:
       Index.php
       File.php
       Login.php
index.php <- Let's say this is your entry point file, this is where you will be autoloading stuff from.

Now let's take a look at your controller Main.php. Two things to keep in mind is that the class name needs to be the name of the file and the namespace for that class is the directory path to that file. So Main.php should look something like this:

<?php

namespace MyProjectControllers;

class Main {

    //Field vars, contructor, methods, etc. all go here.
    
}

?>

You would do the same thing for your your Login model

<?php

namespace MyProjectModels;

class Login {

    //Field vars, contructor, methods, etc. all go here.
    
}

?>

Now in your index.php file (out in the root directory - MyProject) you would make your call to the spl_autoload_register and give it the PSR-0 autoloader.

spl_autoload_register( function ($className) {
    $className = ltrim($className, '\');
    $fileName  = '';
    $namespace = '';
    if ($lastNsPos = strrpos($className, '\')) {
        $namespace = substr($className, 0, $lastNsPos);
        $className = substr($className, $lastNsPos + 1);
        $fileName  = str_replace('\', DIRECTORY_SEPARATOR, $namespace) . DIRECTORY_SEPARATOR;
    }
    $fileName .= str_replace('_', DIRECTORY_SEPARATOR, $className) . '.php';

    require $fileName;
});

//Now you can make your call to your objects without a bunch of include/require statements

$main = new MyProjectControllersMain();  //Instantiates your 'Main' controller
$login = new MyProjectModelsLogin();   //Instantiates your 'Login' model

Hopefully that helps make better sense of it, and again, if you don't want to use namespaces you can always just keep adding closures into the SPL autoload stack. You can have 10 different autoloaders in there if you want and PHP will go through them one by one (in the order you defined them) using each function to try and load a class. However, a couple convention based autoloaders is a bit cleaner and more of a preferred method. Also keep in mind that the autoloader translates both namespace separators and underscores _ as a directory separator. So your Front_controller.php would not autoload as you would expect.

Thursday, April 1, 2021
 
Muazam
 
4

So the problem was that the $class being returned to spl_autoload_register was the namespaceclass name, with the backslash intact. So when I instantiated a new object:

$myObj = new FooClass1();

The include path became /var/www/myApp/classes/FooClass1.php, the backslash breaking the path.

I implemented this to fix the backslash, and it now works, although I do not know why this is necessary.

spl_autoload_register(function($class) {
    include 'classes/' . str_replace('\', '/', $class) . '.class.php';
});
Thursday, April 1, 2021
 
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :