I have encountered an issue with using a combination of the following in PHP:
- A custom classloader "ClassLoader", implemented as a singleton and registered with spl_autoload_register, which does a require_once to include the classes. Nothing special, just some paths to organize the classes on disk.
- A database class "DB" extending the mysqli class. It s created from a factory which currently knows only one instance. It does little more than load the correct config and offer some shortcut methods.
- A custom errorhandler "ErrorHandler", implemented as a singleton which used the DB class to log notices and warnings to a database.
所有这些工作都属于罚款;班轮载荷班级、非行班级都正确进行查询,错误操作员记录数据库中的错误。
...Except when an error occurs before any database operations have been called yet. In this case PHP crashes and crashes hard; no error messages or anything, not even any echo s or var_dump s, not even 4xx or 5xx codes. The browser just reports that nothing has been recieved.
There are a number of "fixes" I ve found:
- Do not extend the mysqli class in my "DB" class; this makes it non-functional, but it seems to indicate extending mysqli causes the problem.
- Autoload my own "DB" class either globally or at the top of my ErrorHandler.php class file.
- Explicitely load the "DB" class using require_once just before getting an instance inside the ErrorHandler class.
我仍然能够把其他班级装上ErrorHandler,但I即时的“DB”,PHP似乎坠毁。
从我看,唯一的合理解释似乎是,我sqli的有些问题涉及在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 ));
DB...
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;
}
}
彩色是单一州,具有一些公共财产。
ErrorHandler
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 />
<b>%s</b>: %s in <b>%s</b> on line <b>%d</b><br /><br />
", $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;
}
}