I've always had this need, especially if I need to work with more people and the files have constant changes, sometimes we lose some problem, or even have to be locating a file and locating the problem, having this need I ended up creating a library just for this kind of situation.
One that reads a part of the file defined by the user: link
And another to do line counting thus displaying beyond the line that occurs the problem (because as I said in another question, sometimes the problem may have occurred a few lines before):
link
Then you could use the code like this:
function obterTrecho($source, $line)
{
if ($line <= 0 || is_file($source) === false) {
return null;
} elseif ($line >= 5) {
$init = $line - 5;
$end = $line + 5;
$breakpoint = 5;
} else {
$init = 0;
$end = 5;
$breakpoint = $line;
}
return array(
'breakpoint' => $breakpoint,
'preview' => explode(EOL, trechoArquivo($source, $init, $end, true))
);
}
function trechoArquivo($path, $init = 0, $end = 1024)
{
if (false === is_file($path)) {
return false;
}
$i = 1;
$output = '';
$handle = fopen($path, 'rb');
while (false === feof($handle) && $i <= $end) {
$data = fgets($handle);
if ($i >= $init) {
$output .= $data;
}
++$i;
}
fclose($handle);
return $output;
}
Note that I have used rb
instead of r
because it can occur from (rarely) needing to read something "binary", its use would look like this:
try {
throw new Exception('Só para mostrar a linha');
} catch (Exception $e) {
var_dump(obterTrecho($e->getFile(), $e->getLine()));
}
It will return something like:
array(
'breakpoint' => 5,
'preview' => array(
'foo();',
'outrocodigo();',
'',
'try {',
'',
' throw new Exception('Só para mostrar a linha');',
'',
'} catch (Exception $e) {',
' var_dump(obterTrecho($e->getFile(), $e->getLine()));',
'}'
)
);
Note that breakpoint
refers to the array item of index 5, but not exactly the line, which you can use to highlight the line that PHP accuses of having the problem, so you can treat this data with something like:
function ExibeErro($file, $line)
{
$source = obterTrecho($file, $line);
$data = $source['preview'];
$breakpoint = $source['breakpoint'];
$lines = count($data);
for ($i = 0; $i < $lines; $i++) {
if ($breakpoint === $i) {
echo '<strong style="color: red;">', htmlspecialchars($data[$i], ENT_QUOTES), '</strong>', EOL;
} else {
echo htmlspecialchars($data[$i], ENT_QUOTES), EOL;
}
}
}
...
try {
throw new Exception('Só para mostrar a linha');
} catch (Exception $e) {
ExibeErro($e->getFile(), $e->getLine()));
}
The interesting thing about it is that you can implement with set_error_handler
so too:
function handlerError($type, $message, $file, $line, $details = null)
{
static $preventDuplicate; //Previne duplicidade dos erros (também é possivel fazer isto pelo php.ini)
$str = '?' . $file . ':' . $line . '?';
if ($preventDuplicate === null) {
$preventDuplicate = '';
}
if (strpos($preventDuplicate, $str) === false) {
$preventDuplicate .= $str;
echo '<h1>Erro: '$message, '</h1>';
ExibeErro($file, $line);
}
return false;
}
function shutodownEvent()
{
//Pega erros de PARSE
$e = error_get_last();
if ($e !== null) {
handlerError($e['type'], $e['message'], $e['file'], $e['line']);
}
}
register_shutdown_function('shutodownEvent');
set_error_handler('handlerError', E_ALL|E_STRICT);