当前位置 主页 > 网站技术 > 代码类 >

    Laravel第三方包报class not found的解决方法

    栏目:代码类 时间:2019-11-06 18:05

    出现的问题

    公司开发使用PHP,技术框架使用Laravel。最近线上出现一个问题,就是上线之后,每次都会出错。查看出错原因,是composer安装的第三方出现class not found。因为这个问题,在线下使用Lumen框架的时候,遇到过,查找问题原因是因为依赖的composer包中composer.json中的”autoload”:{“psr-4”:{}}书写格式问题。解决方法使用命令:composer dump-autoload -o;

    虽然知道问题的所在,但是有一个现象比较费解:这个第三方包已经使用很久了,为什么最近才开始报错呢?下面就开始查找出错原因

    解决方案

    如果确认第三方包已安装,并且正确使用use引用了,尝试执行composer dump-autoload -o

    最终结果

    因为可能篇幅会比较长,所以这里先说明一下最终问题处理结果:原因还未准确定位到,现推测发布服务器环境问题,但因为发布服务器监控服务较多,不允许进行测试,所以具体环境哪个配置导致的问题,还没有定位到。

    下面主要介绍问题解决过程:

     1. 查看laravel autoload
     2. 查看composer源码;
     3. 重新编译composer打印日志;
     4. 分析composer install过程;
     5. 查看php artisan optimize源码

    对分析查找问题的过程感兴趣的同学可以继续往下看。

    问题分析及解决过程

    1. 查找class not found原因

    分析

    既然class not found,确认composer包已经安装。那问题就确定在autoload过程

    查看源码

    首先自动加载入口 public/index.php 中

    require __DIR__.'/../bootstrap/autoload.php';

    然后继续进入 bootstrap/autoload.php 文件

    require __DIR__.'/../vendor/autoload.php';

    然后继续进入 vendor/autoload.php

    // require 自动加载类
    require_once __DIR__ . '/composer/autoload_real.php';
    
    // 真正返回文件列表的操作
    return ComposerAutoloaderInit3f39d071b2e74e04102a9c9b6f221123::getLoader();
    

    进入getLoader()方法中

    public static function getLoader()
    {
     if (null !== self::$loader) {
     return self::$loader;
     }
    
     // 注册自动加载方法,用来后面初始化ClassLoader类
     spl_autoload_register(array('ComposerAutoloaderInit3f39d071b2e74e04102a9c9b6f221123', 'loadClassLoader'), true, true);
     // 初始化ClassLoarder
     self::$loader = $loader = new \Composer\Autoload\ClassLoader();
     spl_autoload_unregister(array('ComposerAutoloaderInit3f39d071b2e74e04102a9c9b6f221123', 'loadClassLoader'));
    
     // 这里zend_loader_file_encoded查了一下,解释为:
     // Returns TRUE if the current file was encoded with Zend Guard or FALSE otherwise. If FALSE, consider disabling the Guard Loader
     // 又查了一下Zend Guard,貌似是php代码加密并提高执行效率的,提高有限,比较鸡肋
     // 打印了一下,发现不存在这个方法,即!function_exists('zend_loader_file_encoded')为true
     $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
     if ($useStaticLoader) {
     // 程序在这里执行
     // 引用ComposerStaticInit类
     require_once __DIR__ . '/autoload_static.php';
    
     // 调用ComposerStaticInit类中的getInitializer方法
     // 主要作用是使用ComposerStaticInit类中的值初始化上面创建的ComposerAutoloader对象中的prefixLengthsPsr4、prefixDirsPsr4、prefixesPsr0、classMap等值
     call_user_func(\Composer\Autoload\ComposerStaticInit3f39d071b2e74e04102a9c9b6f221123::getInitializer($loader));
     } else {
     $map = require __DIR__ . '/autoload_namespaces.php';
     foreach ($map as $namespace => $path) {
      $loader->set($namespace, $path);
     }
    
     $map = require __DIR__ . '/autoload_psr4.php';
     foreach ($map as $namespace => $path) {
      $loader->setPsr4($namespace, $path);
     }
    
     $classMap = require __DIR__ . '/autoload_classmap.php';
     if ($classMap) {
      $loader->addClassMap($classMap);
     }
     }
    
     // 重点在这个方法
     $loader->register(true);
    
     if ($useStaticLoader) {
     $includeFiles = Composer\Autoload\ComposerStaticInit3f39d071b2e74e04102a9c9b6f221123::$files;
     } else {
     $includeFiles = require __DIR__ . '/autoload_files.php';
     }
     foreach ($includeFiles as $fileIdentifier => $file) {
     composerRequire3f39d071b2e74e04102a9c9b6f221123($fileIdentifier, $file);
     }
    
     return $loader;
    }