My site is completely custom, as such I like to know when I have poorly written code. I use set_exception_handler and set_error_handler to use custom classes to log errors to a file. This includes notices and warnings.
Within my own code, this is fine as I get very few logs and those that I do get are things I actually want to fix.
However, i've just started using simplePie and because it's PHP4 compatible I get tons of notices, primarily for things like calling functions statically or passing things by reference incorrectly.
It's too much for me to go through and fix simplePie, if it wasn't I wouldn't be using it in the first place.
Is there a way that I can specifically ignore errors generated by a certain file or class? Here's an overview of what of my very basic exception handling looks like:
set_exception_handler("CustomExceptionHandler");
set_error_handler("customErrorHandler");
/**
* CustomExceptionHandler()
*
* This is used if an exception is thrown that isn't caught.
*
* #param object $e The exception as an object
*/
function CustomExceptionHandler(Exception $e) {
exitToError($e->getMessage());
}
/**
* customErrorHandler()
*
* This is called for any errors no matter what their level.
*/
function customErrorHandler($errno, $errstr, $errfile, $errline) {
if(in_array($errno, array(E_USER_ERROR, E_RECOVERABLE_ERROR))) {
throw new CustomErrorException($errstr, 0, $errno, $errfile, $errline);
} else {
CustomException::logError($errstr, $errno, $errfile, $errline);
}
return FALSE;
}
/**
* class CustomErrorException
*
* Used by custom_error_handler() to convert all fatal
* errors to exceptions.
*
* #see custom_error_handler()
* #see http://www.php.net/manual/en/class.errorexception.php
*/
class CustomErrorException extends CustomException {
/**
* $severity
*
* The severity level of the exception
*
* #access protected
* #var int
*/
protected $severity;
/**
* __construct()
*
* Constructs the new exception
*
* #access public
* #param string $message The Exception message
* #param int $code The Exception code
* #param int $severity The severity level of the exception
* #param string $filename The filename where the exception was thrown
* #param int $lineno The line number where the exception was thrown
*/
public function __construct($message, $code = null, $severity = E_ERROR, $filename = null, $lineno= null) {
$this->message = $message;
$this->code = $code;
$this->severity = (int)$severity;
$this->file = $filename;
$this->line = $lineno;
self::logError($this->message,$this->code,$this->file,$this->line,$this->getTraceAsString());
}
}
/**
* class CustomException
*
* Overwrites Exception to give us more control on how
* exceptions are handled and logged.
*
* #see http://www.php.net/manual/en/language.exceptions.extending.php
*/
class CustomException extends Exception {
/**
* __construct
*
* We call the parent contruct as we still want it to do all its magic. We just want
* overwrite this method so that we can log the error exactly how we want.
*/
public function __construct($message, $code = 0, Exception $previous = NULL) {
parent::__construct($message, $code);
self::logError($this->getMessage(),$this->getCode(),$this->getFile(),$this->getLine(),$this->getTraceAsString());
}
/**
* __toString()
*
* We overwrite this function so that we can use our stringBuilder function.
*/
public function __toString() {
return self::stringBuilder($this->getMessage(),$this->getCode(),$this->getFile(),$this->getLine(),$this->getTraceAsString());
}
/**
* stringBuilder()
*
* We use this method so that we have a standard method of building error
* strings that anything can tap into.
*
* #access public
* #param string $message the exception message
* #param int $code the code assigned to this exception
* #param string $file the file where the exception occurred
* #param int $line the line where the exception occurred
* #param string $trace backtrace
*/
public function stringBuilder($message, $code, $file, $line, $trace='') {
//return "[".date("d-M-Y H:i:s")."] ".$this->getMessage()." in ".$this->getFile().":".$this->getLine()."\nStack trace:\n".$this->getTraceAsString()."\n";
return "[".date("d-M-Y H:i:s")."] ".$message." in ".$file.":".$line."\n";
}
/**
* logError()
*
* We use a method so that we have a standard way of saving errors
* to a log.
*
* We use XML because it's easy to parse.
*
* #access public
* #param string $message the exception message
* #param int $code the code assigned to this exception
* #param string $file the file where the exception occurred
* #param int $line the line where the exception occurred
* #param string $trace backtrace
* #todo We could improve it to write to the xml file using DomDocument
* as laid out here http://www.xml-training-guide.com/append-delete-data-from-xml-using-php.html
*/
public function logError($message, $code, $file, $line, $trace='') {
//Save it to a standard text file to guarentee saving the error
file_put_contents(ROOT_URL.ERROR_LOG_TXT,self::stringBuilder($message, $code, $file, $line, $trace),FILE_APPEND);
}
}
and here is an example of two of the errors simplePie throws up:
[01-Aug-2010 00:50:33] Assigning the return value of new by reference is deprecated in ***\SimplePie.php:738
[01-Aug-2010 00:50:34] Non-static method SimplePie_Misc::parse_date() should not be called statically in ***\SimplePie.php:60
Is there a way that I can specifically ignore errors generated by a certain file or class?
Should be easy! You could check in your custom error handler
function customErrorHandler($errno, $errstr, $errfile, $errline)
whether $errfile is in one of the simplePie files, and in that case return true; silently.
You could inspect the $errfile parameter passed to your error handler to see if the error originates from somewhere inside simplePie.
Documentation: http://php.net/manual/en/function.set-error-handler.php
You have to remove these errors.
1. Remove & in assignments like $foo =& new Object()
2. You can't access method in statticly way if it's not a static method so instead Object::method() you should try using Object->method() or try to change function method() to static function method()
Or the best solution - try to find library in php5
Related
I'am using PhpStorm and have started using #template annotations.
However, I have trouble understanding exactly how they work in relation to #throws tags.
Here are some examples (of fantasy) to explain what I did not understand (or that I am wrong ...).
Let's start with this:
/**
* A custom ErrorException
*/
class CustomErrorException extends ErrorException {}
/**
* This class can throw exceptions
*/
class CanThrowExceptions
{
/**
* Checks `$value` is `true` or throws `$exception`
* #template TrueValue
* #template PassedException as \ErrorException
* #param TrueValue $value Value you want to check
* #param class-string<PassedException> $exception
* #return TrueValue
* #throws PassedException
*/
public static function isTrueOrErrorException($value, string $exception = \ErrorException::class)
{
if ($value) {
return $value;
}
throw new $exception;
}
}
In other words, the isTrueOrErrorException method can throw $exception.
$exception can be ErrorException (default) or another exception that extends ErrorException (like CustomErrorException).
So far, I believe I have used the #templates correctly (is that right?).
Now let's try to get PhpStorm to generate some code. I get this result:
class Example
{
/**
* #return bool
*/
public function test1(): bool
{
return CanThrowExceptions::isTrueOrErrorException(true);
}
/**
* #return bool
*/
public function test2(): bool
{
return CanThrowExceptions::isTrueOrErrorException(true, CustomErrorException::class);
}
}
There is no #throws tag, when I would expect ErrorException for the first method and CustomErrorException for the second.
Needless to say, if I try to edit by hand, the IDE will complain and report a problem to me.
I mean, I think I should normally get this (but this is not the case!):
class Example
{
/**
* #return bool
* #throws \ErrorException
*/
public function test1(): bool
{
return CanThrowExceptions::isTrueOrErrorException(true);
}
/**
* #return bool
* #throws \CustomErrorException
*/
public function test2(): bool
{
return CanThrowExceptions::isTrueOrErrorException(true, CustomErrorException::class);
}
}
So what have I done wrong so far?
Let's go to complicate the code.
I add the valueIsIntOrCustomErrorException() method to the CanThrowExceptions class, which is now like this:
class CustomErrorException extends ErrorException {}
/**
* This class can throw exceptions
*/
class CanThrowExceptions
{
/**
* Checks `$value` is an int or throws `CustomErrorException`
* #template IntValue
* #param IntValue $value
* #return IntValue
*/
public static function valueIsIntOrCustomErrorException($value)
{
//This returns a boolean, so I can't return here
self::isTrueOrErrorException(is_int($value), CustomErrorException::class);
return $value;
}
/**
* Checks `$value` is `true` or throws `$exception`
* #template TrueValue
* #template PassedException as \ErrorException
* #param TrueValue $value Value you want to check
* #param class-string<PassedException> $exception
* #return TrueValue
* #throws PassedException
*/
public static function isTrueOrErrorException($value, string $exception = \ErrorException::class)
{
if ($value) {
return $value;
}
throw new $exception;
}
}
Yet another oddity. Again, no #throws tags for valueIsIntOrCustomErrorException() method!
This is strange, because at least here I would have expected it, since it calls the isTrueOrErrorException() method.
Still, I keep wondering, where am I wrong?
I add some tests of this new method:
class Example
{
//Here same `test1 ()` and `test2 ()` as above
/**
* #return int
*/
public function test3(): int
{
return CanThrowExceptions::valueIsIntOrCustomErrorException(1);
}
}
Again, no #throws tags (should be #throws \CustomErrorException).
Can you help me, with examples or by suggesting corrections to my code? What I did not understand?
Thanks.
I really like the PhpStorm inspection tools. They help me a lot to write better code. Now I have the following situation and I am asking myself what's the best way to deal with such situations.
I have a function f with some precondition, for example like in the following code:
/**
* #param int $x
* #throws PreconditionException x is negative
*/
public function f(int $x): int
{
if ($x < 0) {
throw new PreconditionException("the input x is negative");
}
}
Then I use this function somewhere lets say the following:
f(5);
Now PhpStorm warns me with "Unhandled exception". But in this case I know that the exception will not be thrown, so adding a try block makes not really sense. Should I simply ignore this warning or what's the best way to deal with that?
From phpStorm version 2018.1 you can exclude any exceptions from analysis. Go to preferences->Languages & Frameworks->PHP and open Analysis tab.
Here you can add exceptions to Unchecked Exceptions list
#noinspection tag can be used to instruct PhpStorm to suppress an inspection.
The tag can be used above the line, above the method or on top of the file after <?php word:
/** #noinspection PhpDocMissingThrowsInspection */
/**
*
* Cancels order.
*
* #return bool
*/
public static function cancel()
{
if (!self::inProgress()) return false;
/** #noinspection PhpUnhandledExceptionInspection*/
static::current()->delete();
return true;
}
List of inspections can be found in this gist: https://gist.github.com/discordier/ed4b9cba14652e7212f5
You can also disable it via interface. ALT+ENTER then right arrow and Suppress ...
The correct way is add #throws tag into documentation (PhpStorm manual).
For example:
/**
* #param $userId
* #return array|null
* #throws \Exception <---------------------------
*/
public static function send($userId)
{
if (empty($userId)) {
throw new \Exception("User ID is missing", 1);
}
// ...
}
What helps for me is to set #throws to Null
Example:
/**
* #return SomeObject
* #throws Null
*
*/
In a legacy project, I was confused when I tried finding the usage of a method in phpstorm and without success.
/**
* #param SomeEntity[] $someEntity
*
* #return bool
*/
protected function warmupSomeEntity(array $brandUniverses)
{
// I want to find this method's usage
}
Debugging a bit further, I found that the method is called on the fly in a rather abstract way via dynamic class method invocation:
/**
* #param string $warmer
* #param array $objects
*
* #throws RuntimeException
*/
public function warmupType($warmer, array $objects)
{
$method = "warmup$warmer";
if (method_exists($this, $
$this->{$method}($objects);
} else {
throw new RuntimeException("There is no warmer '$warmer'");
}
}
Is there a phpdoc syntax where I can document that the warmUpType method will call warmupSomeEntity, or warmupSomeOtherEntity so that I can find its usage again if I want to jump to the calling code block again?
The #uses keyword was what I was looking for as it:
Display a link to the documentation for an element, and create a backlink in the other element's documentation to this
It is supported by PhpStorm and the caller is found again.
/**
* #param string $warmer
* #param array $objects
* #uses warmupSomeEntity
* #uses warmupSomeOtherEntity
* #throws RuntimeException
*/
public function warmupType($warmer, array $objects)
{
...
}
I'm trying to send errors and exceptions to raygun.io from a Laravel 4 artisan command, but Laravel appears to have it's own exception handler in place.
Is there a way for me to specify a custom method in my Command? Currently, I'm trying to specify a custom handler for errors and exceptions as follows:
<?php
class ParseCommand extends Command
{
/**
* The console command name.
*
* #var string
*/
protected $name = 'my:parse';
protected $descriptino = '...';
protected $raygun = null;
/**
* __construct
*/
public function __construct()
{
parent::__construct();
// Setup custom error and exception handlers
$raygun_api_key = \Config::get('tms.raygun_api_key');
$this->raygun = new RaygunClient("MUzf+furi8E9tffcHAaJVw==");
set_exception_handler([$this, 'exceptionHandler']);
set_error_handler([$this, 'errorHandler']);
}
/**
* Custom exception handler.
*
* #param $exception
*/
public function exceptionHandler($exception)
{
$this->raygun->SendException($exception);
}
/**
* Custom error handler.
*
* #param $errno
* #param $errstr
* #param $errfile
* #param $errline
*/
public function errorHandler($errno, $errstr, $errfile, $errline)
{
$this->raygun->SendError($errno, $errstr, $errfile, $errline);
}
/**
* Execute the console command.
*
* #return mixed
*/
public function fire()
{
$start_time = microtime(true);
throw new \Exception("Oopsie!");
// Omitted for brevity...
}
}
Off course the handlers never execute, as Artisan is grabbing them with it's own custom implementation.
The files in the folder app/start are only executed while booting the Laravel framework when the according environment is run. This means that app/start/local.php is run when the environment is equal to local and app/start/staging.php is run when the environment is equal to staging. Also the app/start/global.php file is run every time and app/start/artisan.php is run on every artisan execution.
From the documentation: http://laravel.com/docs/errors place the handler
App::error(function(Exception $exception)
{
Log::error($exception);
});
in app/start/artisan for your artisan-only exception handlers.
For example consider following code:
/**
* #param array $array
* #param string $key
* #return mixed
* #throws \InvalidArgumentException
*/
private function getArrayEntry(& $array, $key)
{
if (!array_key_exists($key, $array)) {
throw new \InvalidArgumentException(
'Invalid array of values for location. Missing '.$key.'.'
);
}
return $array[$key];
}
/**
* #param array $data
* #return Location
*/
public function createFromArray(array $data)
{
$this->getArrayEntry($data, 'name');
}
Should the second method have #throws in doc bloc too?
How it is used compared to Java where there is 'throws' keyword?
#throws should be only placed in the docBlock of the method where the exception is thrown.
If you put it up the stack it will be redundant and would be a violation of DRY principle!
In java you can choose between #throws and #exception ..see here
By the way: You are throwing the wrong type of exception. You should throw a \OutOfBoundsException. Otherwise it's a violation of POLA.
\InvalidArgumentException is for an unexpected argument type.