Laravel远程调用asStripeSubscription报Customer类重复声明错误
问题描述
- 运行环境:Laravel 8、PHP 7.3、Cashier 12.10
- 复现特征:本地环境运行完全正常,部署到预发服务器、Travis CI执行PHPUnit测试时,触发
Cannot declare class App\Models\Customer, because the name is already in use错误,报错定位到app/Models/Customer.php的类定义行 - 触发条件:仅当代码中调用
asStripeSubscription()方法时复现,移除该调用后所有流程(用户认证、Stripe支付、订阅管理、webhook同步)均无异常 - 已排除的排查项:
- 数据库问题:测试场景使用
RefreshDatabasetrait,移除CASHIER_MODEL: App\Models\Customer环境变量后会正常触发模型缺失错误,说明环境变量读取正常 - 缓存/自动加载问题:已执行
php artisan optimize:clear、composer dump-autoload、重启预发服务器、清空Travis CI缓存,问题仍存在 - 代码位置问题:已将该调用迁移到其他模型、控制器,问题仍复现
- 数据库问题:测试场景使用
相关代码片段
Customer模型自定义方法:
public function subscriptionRenewalDate() : string { $subscription = $this->subscriptions()->active()->first()->asStripeSubscription(); return Carbon::createFromTimeStamp($subscription->current_period_end)->format('F jS, Y'); }
Blade模板调用代码:{{ auth()->user()->subscriptionRenewalDate() }}
报错日志
[2021-03-22 10:29:23] production.ERROR: Cannot declare class App\Models\Customer, because the name is already in use {"userId":1127215,"exception":"[object] (Symfony\Component\ErrorHandler\Error\FatalError(code: 0): Cannot declare class App\Models\Customer, because the name is already in use at /var/app/current/app/Models/Customer.php:13)
排查解决方案
- 检查重复类定义
- 全局搜索项目内所有包含
class Customer定义的文件,确认是否存在两个不同文件定义了同一完全限定类名App\Models\Customer - 重点检查Laravel默认的
app/User.php文件,确认是否误修改其命名空间或类名,与app/Models/Customer.php定义冲突
- 全局搜索项目内所有包含
- 校验Composer自动加载配置
- 打开
composer.json,检查autoload.files数组是否误加入app/Models/Customer.php:该配置会强制每次请求加载该文件,配合自动加载机制会导致类定义重复执行,若存在则删除该项 - 执行
composer dump-autoload -o生成权威类映射,确认生成的vendor/composer/autoload_classmap.php中仅存在一个App\Models\Customer对应的文件路径
- 打开
- 排查Opcache配置影响
- 预发/CI环境通常开启Opcache,执行
php -i | grep opcache确认配置:- 若
opcache.validate_timestamps=0,部署时旧类缓存可能残留,需手动重置Opcache(执行opcache_reset()或重启PHP-FPM进程) - 开启
opcache.dups_fix配置,兼容类重复声明的场景
- 若
- 预发/CI环境通常开启Opcache,执行
- 验证Cashier配置正确性
- 打开
config/cashier.php,确认model配置项为env('CASHIER_MODEL', App\Models\Customer::class),未硬编码错误命名空间 - 确认
App\Models\Customer模型正确引入Laravel\Cashier\Billabletrait,未手动引入Stripe SDK的Stripe\Customer类造成命名空间冲突
- 打开
- 定位二次加载触发点
- 在
app/Models/Customer.php的类定义行前加入调试代码:if (class_exists('App\Models\Customer')) { debug_print_backtrace(); die; } - 触发报错后查看堆栈输出,即可定位到具体触发二次加载
Customer.php的代码位置,通常为手动require/include语句或错误的自动加载规则
- 在
内容的提问来源于Stack Exchange,提问作者Chuck Le Butt
相关产品推荐
相关产品推荐

