gpt4 book ai didi

php - 在带有自动加载器的错误处理程序中使用 MySQLi 扩展类

转载 作者:可可西里 更新时间:2023-11-01 07:41:46 25 4
gpt4 key购买 nike

我在 PHP 中使用以下组合时遇到问题:

  • 自定义类加载器“ClassLoader”,作为单例实现并使用 spl_autoload_register 注册,它执行 require_once 以包含类。没什么特别的,只是一些在磁盘上组织类的路径。
  • 扩展 mysqli 类的数据库类“DB”。它是从一个目前只知道一个实例的工厂创建的。它只是加载正确的配置并提供一些快捷方法。
  • 自定义错误处理程序“ErrorHandler”,实现为使用 DB 类将通知和警告记录到数据库的单例。

所有这些工作正常;类加载器加载类,数据库类正确执行查询,错误处理程序将错误记录在数据库中。

...除非在调用任何数据库操作之前发生错误。在这种情况下,PHP 会崩溃并且崩溃得很厉害;没有错误消息或任何东西,甚至没有任何 echo 或 var_dump,甚至没有 4xx 或 5xx 代码。浏览器只是报告没有收到任何东西。

我发现了一些“修复”:

  • 不要在我的“DB”类中扩展 mysqli 类;这使它无法正常工作,但它似乎表明扩展 mysqli 会导致问题。
  • 在全局或在我的 ErrorHandler.php 类文件的顶部自动加载我自己的“DB”类。
  • 在 ErrorHandler 类中获取实例之前,使用 require_once 显式加载“DB”类。

我仍然可以在 ErrorHandler 中自动加载其他类,但是当我实例化“DB”时,PHP 似乎崩溃了。

据我所知,唯一合理的解释似乎是 mysqli 中的某些内容在 ErrorHandler 类中首次实例化的范围方面存在问题,因为所有有效的修复似乎都共享范围方面,但事实并非如此似乎完全没有任何意义。

有人知道这里发生了什么吗?

类加载器...

class ClassLoader {
private $_paths = array();

private function __construct() {
// ... bunch of $this->append() calls with all paths and 3rd party libs
}

private static $_instance = null;
public static function get() {
if (self::$_instance === null) {
self::$_instance = new self();
}
return self::$_instance;
}

public function append($path, $format = '$.class.php') {
if (!array_key_exists($path, $this->_paths)) {
$this->_paths[$path] = $format;
return true;
}
return false;
}

public function autoload($class_name) {
foreach ($this->_paths as $path => $format) {
$file = $path.'/'.str_replace('$', $class_name, $format);
if (file_exists($file)) {
require_once($file);
return true;
}
}
return false;
}
}

$autoloader = ClassLoader::get();
$autoloader->append(dirname(__FILE__).'/classes');
spl_autoload_register(array($autoloader, 'autoload'));

数据库...

class DB extends mysqli {
private static $_instances = array();
public static function get(Config $config) {
$hash = md5(serialize($config));
if (!array_key_exists($hash, self::$_instances)) {
self::$_instances[$hash] = new self($config);
}
return self::$_instances[$hash];
}

private $_prefix = '';
private $_die = false;
public function dieOnError($die) { $this->_die = $die; }

private function __construct(Config $config) {
parent::__construct(
$config->host
, $config->username
, $config->password
, $config->database
);

if ($this->connect_error) {
_report_error($this->connect_errno, $this->connect_error);
}

$this->_prefix = $config->prefix;
}
}

Config 是一个具有一些公共(public)属性的单例。

错误处理器

class ErrorHandler extends Object {
/*
* Strip recursion problems in the backtrace
*/
private static function _filter_backtrace($array, $depth = 0) {
$result = array();

foreach ($array as $name => $value) {
switch (gettype($value)) {
case 'object':
case 'unknown type':
case 'resource':
break;

case 'array':
//$result[$name] = self::_filter_backtrace($value);
break;

default:
//$result[$name] = $value;
}
}

return $result;
}

private function _handle_db($errno, $errstr, $errfile, $errline, $backtrace) {
$db = DB::get(Config::get());
$db->dieOnError(true); // prevents infinite loops in error handler
// DB query here
$db->dieOnError(false); // for non-dying.
}

private function __construct() {
}

private static $_instance = null;
public static function get() {
if (self::$_instance === null) {
self::$_instance = new self();
}
return self::$_instance;
}

public function handle($errno, $errstr, $errfile, $errline) {
// No error? Return without reporting
if (!($errno & error_reporting())) {
return;
}

// Type of error
switch ($errno) {
case E_NOTICE:
case E_USER_NOTICE:
$errors = "Notice";
break;
case E_WARNING:
case E_USER_WARNING:
$errors = "Warning";
break;
case E_ERROR:
case E_USER_ERROR:
$errors = "Fatal Error";
break;
default:
$errors = "Unknown";
break;
}

//$backtrace = self::_filter_backtrace(array_shift(debug_backtrace()));
$backtrace = array();

switch (Config::get()->error_log) {
case 'db':
ErrorHandler::_handle_db($errno, $errstr, $errfile, $errline, $backtrace);
break;

default:
// Dump
if (ini_get("display_errors")) {
printf("<br />\n<b>%s</b>: %s in <b>%s</b> on line <b>%d</b><br /><br />\n", $errors, $errstr, $errfile, $errline);
}

// Log
if (ini_get('log_errors')) {
error_log(sprintf("PHP %s: %s in %s on line %d", $errors, $errstr, $errfile, $errline));
}
break;
}

// Exit/return strategy
switch ($errno) {
case E_ERROR:
case E_USER_ERROR:
die();
break;
}
return TRUE;
}
}

最佳答案

当数据库不可用时,您无法使用错误处理程序登录数据库。

如果在初始化数据库之前调用错误处理程序,就会出现这种情况。

您需要为这种情况实现回退。错误处理程序可以创建数据库,或者您需要先创建数据库,或者在这种情况下记录到文件,因为文件通常可用。

无论如何要调试您的问题,请考虑启用错误记录到错误日志中(PHP 已经提供了这个,只需配置它),然后您在您触发时找出您的具体问题是什么该问题将为您提供更多信息以更好地解决您的问题(例如,消除记录器和数据库之间依赖关系的缺陷)。

关于php - 在带有自动加载器的错误处理程序中使用 MySQLi 扩展类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8048446/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com