我的目标不是编辑所有内容,而是
As per hakre
我还定义了处理时递归次数的限制。属性数组
$aMax
可以进行调整。它的当前值不会影响演示-你必须使用更低的值才能看到用最后一个元素切割的数组,比如:
[...] => 3 more
该类有3个入口点来注册所有不同的错误罪魁祸首:
-
ErrorHandler:: err_handler()
用于运行时错误/警告/提示等。。。
-
ErrorHandler:: exc_handler()
对于例外情况
-
ErrorHandler:: die_handler()
用于脚本流产
他们必须注册(见下文),然后该类在所有三个场合/来源中都是相同的。如果您检查每个处理程序,您将只注意到细微的差异。类从不需要实例。
<?php
class ErrorHandler {
public static $sMatchIndex= '#pass|time#i';
public static $sMatchFunction= '#connect$|login#i';
public static $aMax= array
( 'recursion_count' => 30
, 'recursion_depth' => 5
, 'array_elements' => 20
, 'class_properties'=> 15
, 'parameters' => 20
);
private static $bRedactAllStrings= FALSE;
private static $aMaxCount= array();
public static function as_per_type
( $vValue // Variable of any data type.
, &$sType // Recognized data type; is needed later, too.
, $vKey= '' // Potential array index to test for password-like name.
) {
$sType= gettype( $vValue );
switch( $sType ) {
case 'array':
return self:: recurse_array( $vValue );
case 'object':
return self:: recurse_object( $vValue );
case 'string':
if( self:: $bRedactAllStrings ) {
return '**REDACTED_PER_FUNCTION**';
} else
if( $vKey&& preg_match( self:: $sMatchIndex, $vKey ) ) {
return '**REDACTED_PER_INDEX**';
} else
return "'$vValue'";
default:
return $vValue;
}
}
public static function recurse_object
( $oInput // Object with any properties.
) {
if( self:: $aMaxCount['recursion_count']> self:: $aMax['recursion_count']
|| self:: $aMaxCount['recursion_depth']> self:: $aMax['recursion_depth']
) {
return 'O('. count( get_object_vars( $oInput ) ). ')';
} else self:: $aMaxCount['recursion_count']++;
self:: $aMaxCount['recursion_depth']++;
$aObj= get_object_vars( $oInput );
$aOutput= array();
$iProperty= 1;
foreach( $aObj as $iObj=> $vObj ) {
if( $iProperty> self:: $aMax['class_properties'] ) {
$aOutput['...']= (count( $aObj )- $iProperty+ 1). ' more';
break;
} else $iProperty++;
$vValue= self:: as_per_type( $oInput-> $iObj, $sType, $iObj );
$aOutput["$iObj ($sType)"]= $vValue;
}
self:: $aMaxCount['recursion_depth']--;
return $aOutput;
}
public static function recurse_array
( $aInput // Array with any elements.
) {
if( self:: $aMaxCount['recursion_count']> self:: $aMax['recursion_count']
|| self:: $aMaxCount['recursion_depth']> self:: $aMax['recursion_depth']
) {
return 'A('. count( $aInput ). ')';
} else self:: $aMaxCount['recursion_count']++;
self:: $aMaxCount['recursion_depth']++;
$aOutput= array();
$iElement= 1;
foreach( $aInput as $iKey=> $vValue ) {
if( $iElement> self:: $aMax['array_elements'] ) {
$aOutput['...']= (count( $aInput )- $iElement+ 1). ' more';
break;
} else $iElement++;
$sKey= self:: as_per_type( $iKey, $sTypeKey );
$sValue= self:: as_per_type( $vValue, $sTypeValue, $iKey );
if( $sTypeValue== 'object' ) $sTypeValue.= ' '. get_class( $vValue );
$aOutput["$sKey ($sTypeValue)"]= $sValue;
}
self:: $aMaxCount['recursion_depth']--;
return $aOutput;
}
public static function redact_backtrace
( $aTrace // Stack trace array to be parsed.
) {
self:: $aMaxCount= array
( 'recursion_count'=> 0
, 'recursion_depth'=> 1
);
foreach( $aTrace as $iFunc=> $aFunc ) {
self:: $bRedactAllStrings= FALSE;
if( isset( $aFunc['object'] ) ) {
$aTrace[$iFunc]['object']= self:: recurse_object( $aTrace[$iFunc]['object'] );
}
if( isset( $aFunc['function'] ) ) {
self:: $bRedactAllStrings= preg_match( self:: $sMatchFunction, $aFunc['function'] );
}
if( isset( $aFunc['args'] ) ) {
$iRemoved= 0;
while( count( $aTrace[$iFunc]['args'] )> self:: $aMax['parameters'] ) {
array_pop( $aTrace[$iFunc]['args'] );
$iRemoved++;
}
$aTrace[$iFunc]['args']= self:: recurse_array( $aTrace[$iFunc]['args'] );
if( $iRemoved ) $aTrace[$iFunc]['args']['...']= $iRemoved. ' more';
}
}
return $aTrace;
}
private static $bHeadersSent= FALSE;
public static function err_log
( $aLog // Array to be saved.
) {
if( !self:: $bHeadersSent ) {
header( 'content-type: text/plain' );
self:: $bHeadersSent= TRUE;
}
print_r( $aLog );
}
public static function err_handler
( $iError // See https://www.php.net/manual/en/errorfunc.constants.php
, $sText // Error message.
, $sFile // PHP file which was parsed.
, $iLine // Line of error in PHP file.
) {
$aTrace= debug_backtrace();
unset( $aTrace[0] );
self:: err_log
( array
( 'where' => 'Error handler'
, 'file' => $sFile
, 'line' => $iLine
, 'code' => $iError
, 'msg' => $sText
, 'trace' => self:: redact_backtrace( $aTrace )
)
);
}
public static function exc_handler
( $e // Exception
) {
self:: err_log
( array
( 'where' => 'Exception handler'
, 'file' => $e-> getFile()
, 'line' => $e-> getLine()
, 'code' => $e-> getCode()
, 'msg' => $e-> getMessage()
, 'trace' => self:: redact_backtrace( $e-> getTrace() )
, 'class' => get_class( $e )
)
);
}
public static function die_handler() {
$aErr= error_get_last();
if( !count( $aErr ) ) return;
$aTrace= debug_backtrace();
unset( $aTrace[0] );
self:: err_log
( array
( 'where' => 'Shutdown handler'
, 'file' => $aErr['file']
, 'line' => $aErr['line']
, 'code' => $aErr['type']
, 'msg' => $aErr['message']
, 'trace' => self:: redact_backtrace( $aTrace )
)
);
}
}
set_error_handler ( array( 'ErrorHandler', 'err_handler' ), E_ALL );
set_exception_handler ( array( 'ErrorHandler', 'exc_handler' ) );
register_shutdown_function ( array( 'ErrorHandler', 'die_handler' ) );
class Example {
public $iNumber = 12345;
public $sPassword = 'secret';
public $sInfo = 'a password?';
public function login( $sUser, $sPass ) {
echo( array() );
}
public function test( $a, $b ) {
$this-> login( 'username', 'password' );
unset( $a['obj'] );
1/ 0;
1+ $x;
throw new Exception( 'TestException' );
}
}
$aFirst= array
( 'string' => 'Text'
, 'int' => 42
, 'float' => 3.1415
, 'bool' => TRUE
, 'array' => array
( 'key' => 'value'
, 'db_password' => 'adminadmin'
)
, 'obj' => new DateTime
, 'pass' => '12345'
, 110 => 'ordinal index'
);
$aSecond= array
( 'no index identifying a password'
, 'username'
);
$oTest= new Example;
$oTest-> test( $aFirst, $aSecond );
这比
reformed's answer
目标受众是对PHP有信心或想投入时间来理解它的人。我试图通过解释尽可能多地发表评论。