Laravel框架下如何禁止指定类调用全局辅助函数app()
需求可实现,以下是两种常用落地方案
方案1:运行时拦截(符合你给出的代码示例效果)
Laravel的全局辅助函数定义时都会做function_exists判断,你可以在Laravel加载自带辅助函数之前提前定义app()函数,结合调用栈校验实现拦截:
实现步骤
- 新建自定义辅助函数文件
app/helpers/custom_app.php,写入以下代码:
<?php // 全局存储禁止使用指定函数的类列表 $GLOBALS['__forbidden_func_map'] = []; if (!function_exists('app')) { function app($make = null, array $parameters = []) { // 获取调用app()的类信息 $callTrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2); $callerClass = $callTrace[1]['class'] ?? null; // 校验当前类是否被禁止调用app() if ( $callerClass && isset($GLOBALS['__forbidden_func_map'][$callerClass]) && in_array('app', $GLOBALS['__forbidden_func_map'][$callerClass]) ) { throw new \RuntimeException(sprintf('类 %s 禁止直接调用app(),请使用项目封装的权限校验实例创建方法', $callerClass)); } // 走Laravel原生的容器实例获取逻辑 return \Illuminate\Container\Container::getInstance()->make($make, $parameters); } } if (!function_exists('forbid_use_of_function')) { function forbid_use_of_function(string $funcName) { $callTrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2); $callerClass = $callTrace[1]['class'] ?? null; if (!$callerClass) return; if (!isset($GLOBALS['__forbidden_func_map'][$callerClass])) { $GLOBALS['__forbidden_func_map'][$callerClass] = []; } if (!in_array($funcName, $GLOBALS['__forbidden_func_map'][$callerClass])) { $GLOBALS['__forbidden_func_map'][$callerClass][] = $funcName; } } }
- 修改
composer.json的自动加载配置,让自定义辅助函数优先于Laravel自带的辅助函数加载:
{ "autoload": { "files": [ "app/helpers/custom_app.php", "vendor/laravel/framework/src/Illuminate/Foundation/helpers.php" ] } }
- 执行
composer dump-autoload使配置生效。
配置完成后你给出的示例代码就会按预期抛出异常。
如果你需要的是「仅允许特定类使用app()」的白名单逻辑,不需要forbid_use_of_function方法,直接在自定义的app()函数里配置允许调用的类列表,不在列表内的调用直接抛异常即可,逻辑更简单。
方案2:静态代码检测(更适合多人协作场景)
如果不想改运行时代码,可以用PHPStan/Psalm等静态检测工具添加自定义规则,代码提交/合并前自动扫描所有调用app()的位置,不符合规则的直接阻断提交,从开发流程层面避免开发者绕过权限逻辑。
内容的提问来源于stack exchange,提问作者cr001
相关产品推荐
相关产品推荐

