PHP Composer 的一个小坑
今天遇到一个问题,在一个 Laravel 项目中执行数据库迁移和填充时,报了一个找不到类定义的错误,错误提示如下:Class MenusTableSeeder does not exist
类定义文件确定是存在的,命名也没问题。第一感觉是重新生成下 composer 的自动加载文件。可执行如下命令生成:composer dump-autoload
常规情况到这一般都能解决问题,网上能搜到的相关主题也基本是这个办法可以解决此类问题。但这个项目还是报这个类不存在的错误。怀疑composer引入的文件是不是哪损坏了,重新 composer install 安装一遍,还是报错。此时还有一点比较诡异的是另外一台机器上执行同样的操作不会报这个类不存在的错误,一切正常。
此时,我怀疑是 composer 的 bug 。。。
又 google 了下,没看到相关问题的描述。没办法,只有去看看 composer 的源码是怎么生成的自动加载相关文件。经过一番debug,找到了关键代码所在,有兴趣的可以去看看:https://github.com/composer/composer/blob/...
在这个 findClasses 函数中,有这么一个去除代码中 heredoc 或 nowdoc 的操作:
// strip heredocs/nowdocs
$contents = preg_replace('{<<<[ \t]*([\'"]?)(\w+)\\1(?:\r\n|\n|\r)(?:.*?)(?:\r\n|\n|\r)(?:\s*)\\2(?=\s+|[;,.)])}s', 'null', $contents);
问题就出在这个正则。对于内容比较长的类源文件,这个正则替换可能会直接报错返回null,这样就导致 composer 无法识别出该类,从而你的应用中就会报类不存在的错误。
通过调用 preg_last_error() 函数可以获取正则错误代码。我这里返回的错误代码为 2,也就是 PREG_BACKTRACK_LIMIT_ERROR,意思是回溯限制错误。这个错误受 php 配置影响,可以把 pcre.backtrack_limit 参数设置更大或者直接设置成-1不受限制(可能会造成性能问题,谨慎操作)。这也是前面提到的为什么有的机器上正常,有的机器上又不正常,原因就在于这个配置不同。
OK,到此弄清楚是什么原因了。解决办法:1、可以将 pcre.backtrack_limit 参数设置大点再试试 2、看是否能减小类源文件中 heredocs/nowdocs 字符串的大小。此处我的解决办法是直接把这个超长 heredocs 字符串独立到sql文件中,代码中读取文件内容即可。
最后,这到底算不算 composer 的一个bug呢^_^ 个人觉得这里的代码可以写的更完善些,对 preg_replace 的返回值进行错误判断,对于异常情况可以在此直接抛出异常,让用户很清晰的知道是什么原因出错了,进而迅速解决问题。而不是最终这个类找不到定义,又不知道是哪出问题了。。。
本作品采用《CC 协议》,转载必须注明作者和本文链接
很赞
层层深入,厉害 :+1: