今天遇到一个奇怪的问题,在命令行下运行一个脚本,使用 php cron_test.php 可以正常运行;但是,回到上一级目录 cd ../ ,然后
使用 php async_script/cron_test.php 却不能完整运行,遇到加载其他类的地方就停止了,但是也不报错,try...catch...也没用信
息,各种调试了好久,后来猜测这个类是不是没有被加载进来呢?但是又一想,如果没有加载到,也会报错啊,这啥提示也没有。。。
情况如下:
目录结构如下:
dc_leba_new\
async_script\
Core\
Lib\
Common.php
Logic\
Factory.php
Logs\
vendor\
...
cron_test.php
...
cron_test.php的代码
require('Lib/Common.php');
use Logic\Factory;
class cron_test
{
public $logTag = 'cron_test';
public $log;
public function main(){
echo 1 .PHP_EOL;
$this->log = Factory::getLogger();
echo 2 .PHP_EOL;
$this->log->info($this->logTag, 'cron start');
}
}
$obj = new cron_test();
$obj->main();
执行 php async_script/cron_test.php 只输出 1 然后就退出了。
执行 cd async_script
php cron_test.php 输出 1 和 2,完整的执行了。
考虑到可能是类加载出了问题,于是查看 Lib/Common.php
<?php
use \Logic\Factory;
$root = dirname(__DIR__);
require $root . '/vendor/autoload.php';
set_exception_handler('output_exception');
set_error_handler('output_error');
register_shutdown_function('output_shutdown');
spl_autoload_register('my_autoload');
date_default_timezone_set('Asia/Shanghai');
ini_set('error_reporting', 'E_ALL');
function output_exception($e){
$logs = Factory::getLogger();
$msg = $e->getFile() . ' | lime ' . $e->getLine() . ' | ' . $e->getMessage();
$logs->error('sys_exception', $msg);
}
function output_error($errno, $errstr, $errfile, $errline){
$logs = Factory::getLogger();
$msg = $errfile . ' | lime ' . $errline . ' | ' . $errstr . ' | errno ' . $errno;
$logs->error('sys_error', $msg);
}
function output_shutdown(){
$logs = Factory::getLogger();
$data = error_get_last();
if(isset($data['message']) && !is_null($data['message'])) {
$msg = $data['file'] . ' | line ' . $data['line'] . ' | ' . $data['message'];
$logs->fatal('sys_shutdown', $msg);
}
}
function my_autoload($class_name){
$full = str_replace('\\', '/', $class_name);
require_once $full . '.php';
}
试着在 my_autoload 函数中打印 $full, 输出的是 Logic/Factory ,于是发现了问题所在
当我执行 php async_script/cron_test.php 时,
php解释器的当前目录是在 dc_leba_new ,因此我的 my_autoload 会加载 dc_leba_new/Logic/Factory 显示是没有的。
那么第二题又来了,既然找不到这个文件,那php解释器为什么不报错呢?
仔细分析Connme,php文件,虽然定义了各种捕获错误与异常的方法,但是别忘了,他们只能捕获引入的文件中的错误,当前文件的错误是不捕获的,
也不提示,这一点我们研究那些开源框架就知道了,知道了问题后就来修改:
Common.php文件修改后如下:
<?php
use \Logic\Factory;
define('ROOT', dirname(__DIR__));
require ROOT . '/vendor/autoload.php';
set_exception_handler('output_exception');
set_error_handler('output_error');
register_shutdown_function('output_shutdown');
spl_autoload_register('my_autoload');
date_default_timezone_set('Asia/Shanghai');
ini_set('error_reporting', 'E_ALL');
function output_exception($e){
$logs = Factory::getLogger();
$msg = $e->getFile() . ' | lime ' . $e->getLine() . ' | ' . $e->getMessage();
$logs->error('sys_exception', $msg);
}
function output_error($errno, $errstr, $errfile, $errline){
$logs = Factory::getLogger();
$msg = $errfile . ' | lime ' . $errline . ' | ' . $errstr . ' | errno ' . $errno;
$logs->error('sys_error', $msg);
}
function output_shutdown(){
$logs = Factory::getLogger();
$data = error_get_last();
if(isset($data['message']) && !is_null($data['message'])) {
$msg = $data['file'] . ' | line ' . $data['line'] . ' | ' . $data['message'];
$logs->fatal('sys_shutdown', $msg);
}
}
function my_autoload($class_name){
$full = str_replace('\\', '/', $class_name);
$file = ROOT . '/' . $full . '.php';
if(file_exists($file)){
require_once $file;
}else{
// 考虑到一些没有定义命名空间的类,和系统内置的类
$ext = $full . '.php';
require_once $ext;
}
}
主要改动:
1、增加了ROOT常量
__DIR__ 的值就是Common.php所在的文件夹 即 Lib,再使用 dirname() 函数,得到 async_script,就是项目根目录了。
2、将 my_autoload() 函数改为 绝对路径加载,这样不管在哪个目录下执行都不会有问题。
3、待改进的是:
1、将自定义异常与错误处理单独放一个文件
set_exception_handler('output_exception');
set_error_handler('output_error');
register_shutdown_function('output_shutdown');
spl_autoload_register('my_autoload');
2、将捕获处理方法放到另一个文件中,因为不能排除这里也会有错
function output_exception($e){
$logs = Factory::getLogger();
$msg = $e->getFile() . ' | lime ' . $e->getLine() . ' | ' . $e->getMessage();
$logs->error('sys_exception', $msg);
}
function output_error($errno, $errstr, $errfile, $errline){
$logs = Factory::getLogger();
$msg = $errfile . ' | lime ' . $errline . ' | ' . $errstr . ' | errno ' . $errno;
$logs->error('sys_error', $msg);
}
function output_shutdown(){
$logs = Factory::getLogger();
$data = error_get_last();
if(isset($data['message']) && !is_null($data['message'])) {
$msg = $data['file'] . ' | line ' . $data['line'] . ' | ' . $data['message'];
$logs->fatal('sys_shutdown', $msg);
}
}
3、将 my_autoload() 方法单独放到一个文件,这是最容易出错的。
于是这引发了我对 php中,当前路径和相对路径的思考,参看另外一篇文章。
关于回写脚本框架与自动加载autoload的一点总结
猜你喜欢
转载自blog.csdn.net/raoxiaoya/article/details/92371941
今日推荐
周排行