0
votes

I'm updating a project and I've decided to update my Twig version. I deliberately haven't updated it in the past because of the fact you now need to use Composer, but I've eventually given in to this and decided to install a newer version.

However, it's messing around with my Autoload functions and not loading Twig properly, and I really don't want to have to use it. In a blank file with only the code to autoload Composer it works, so I know my autoloader is clashing. I can see that I'm going to have to use it to some degree, because Twig now requires it. I'm only interested in using it for third-party code, and I don't want to use it for anything else. So what I'm looking for is my own autoloader to try first, and then if I can't load a class by my own means, to try using the Composer autoloader. Third-party code exists in a subdirectory of "Lib". So With Twig, it sits in Lib/vendor/twig/twig/src.

At the moment, I'm checking the first part of the namespace and if it isn't matching my own, I'm trying to load the Composer autoload.php file in Lib/vendor/autoload.php, and then returning back out of my autoload function. But this doesn't seem to be finding the class.

Is what I'm trying to do actually possible? How would I approach something like this?

** Edit - Current Autoloader **

public static function autoloader($classname)
{
    /* Separate by namespace */
    $bits = explode('\\', ltrim($classname, '\\'));
    $vendor = array_shift($bits);

    /* If this doesn't belong to us, ignore it */
    if ($vendor !== 'Site')
    {
        // We don't want to interfere here
        if ($vendor == 'Forum')
            return;

        // Try to see if we can autoload with Composer, if not abort
        include_once(SITE_ROOT.'include/Lib/vendor/autoload.php');
print_r(spl_autoload_functions ( ));
        return;
    }

    $class = array_pop($bits);
    $namespace = empty($bits) ? 'Site' : ('Site\\'.implode('\\', $bits));

    $sources_dir = false;
    $path = SITE_ROOT.'include/';
    foreach (array_merge($bits, array($class)) as $i => $bit)
    {
        if ($i === 0 && $bit == 'Lib')
        {
            $bit = mb_strtolower($bit);
            $sources_dir = true;
        }
        else if (preg_match("/^[a-z0-9]/", $bit)) // Applications only contain lowercase letters
        {
            if ($i === 0)
                $path .= 'apps/';
            else
                $sources_dir = true;
        }
        else if ($i === 1 && ($bit == 'Api' || $bit == 'Cli' || $bit == 'Ajax')) // The API/CLI/AJAX interfaces have slightly different rules ....
        {
            $bit = mb_strtolower($bit);
            $sources_dir = true;
        }
        else if ($sources_dir === false)
        {
            if ($i === 0)
            {
                $path .= 'components/';
            }
            else if ($i === 1 && $bit === 'Application')
            {
                // Do nothing
            }
            else
            {
                $path .= 'sources/';
            }

            $sources_dir = true;
        }

        $path .= $bit.'/';
    }

    /* Load it */
    $path = \substr($path, 0, -1).'.php';
    if (!file_exists($path))
    {
        $path = \substr($path, 0, -4).\substr($path, \strrpos($path, '/'));
        if (!file_exists($path))
        {
            return false;
        }
    }

    require_once($path);

    if (interface_exists("{$namespace}\\{$class}", FALSE))
    {
        return;
    }

    /* Doesn't exist? */
    if (!class_exists("{$namespace}\\{$class}", FALSE))
    {
        trigger_error("Class {$classname} could not be loaded. Ensure it has been properly prefixed and is in the correct namespace.", E_USER_ERROR);
    }
}
1
How does your current autoload look like? - Zoli Szabó
I've updated my question and added the code! - Chris98

1 Answers

1
votes

It might be too late to load Composer's autoload.php within the custom autoload.

You should not worry too much about performance issues and just load both your custom autoloader and Composer's autoload one after to other. You can optimize a little by prioritizing these autoloaders based on which classes will you load more often (your own or those installed via Composer).

Also, your own/custom autoloader should only care about successful loading and not throw errors if something is not found. Leave that to PHP, this could help with compatibility with other autoloaders.