I need to write to log some data when exception occurred, since it is dynamic data and I need the message I tried with simple code, just to write 'Boom' if exception occurred.
However just the automatic exception data written in logs (as before the try catch).
can someone advise how to print to log in the catch?
I just need to add additional text to the exception, just to be more specific
try {
$sheet->setCellValue($cell,$innervalue);
} catch(Exception $e) {
$message = 'Can not set value: '.$innervalue .' in cell ' .$cell .$headerArray[$headerIndex];
\Log::info('boom');
}
and in the logs nothing displayed
php artisan make:Exception SomeAweSomeException
This way you have your own controle of how the exception should look and handle. Also you can use standards wich makes you code look cleaner.
class SomeCustomException extends Exception
{
// ...
/**
* Get the exception's context information.
*
* #return array
*/
public function context()
{
return ['order_id' => $this->orderId];
}
}
use Exception;
class SetDeliverDateToFarAwayException extends Exception
{
public function __construct()
{
parent::__construct(
'Selecting more than three days into the future is not allowed'
);
}
}
and now my method wich creates the error message.
/**
* Finalizes the scheduler
*
* #return string
* #throws SetDeliverDateToFarAwayException|Throwable
*/
public function set(): string
{
$today = Carbon::now();
$deliver = new Carbon();
$deliver->year($this->year ?? $today->year);
$deliver->month($this->month ?? $today->month);
$deliver->day($this->day ?? $today->day);
$deliver->hour($this->hour ?? $today->hour);
$deliver->minute($this->minute ?? $today->minute);
#Mail gun can max schedule mail for 3 days in the future. So we throw an Exception if the date is to big.
throw_if($deliver->diffInHours($today) > 72, new SetDeliverDateToFarAwayException());
return Mail::schedule($deliver->toDateTimeString());
}
this what worked for me
try {
$sheet->setCellValueExplicit('WELL DONE');
}
catch (\Exception $e) {
$errorMsg = 'the value of:\' ' .$innervalue . '\' in cell ' . $cell . ' in header: ' . $headerArray[$headerIndex] . 'problematic' ;
\Log::error($errorMsg);
\Log::error($e->getMessage());
\Log::error($e->getTraceAsString());
throw new Exception($e->getMessage());
}
To get the exception log message use it like this -
try {
} catch(Exception $e) {
Log::info(json_encode($e->getMessage()));
}
Related
I learned that I can define my error codes like this:
class Hello
{
/** My own error codes */
const OK = 0;
const ERROR = 1;
const OTHER = 2;
function Test()
{
/** Return the error code if an error was occurred */
if(an_error_occurred)
return self::ERROR;
/** Simulate some simple result. */
return rand(0, 10);
}
}
but I have some trouble about this:
if($Hello->Test() == Hello::ERROR)
exit('Something happened.');
It'll still exit even there's no error occurred but the value which $Hello->Test() gave equals 1,
how do I solve this problem?
Or there's an better way to define my own error code?
You shouldn't mix meanings for return values. As others have mentioned, Exceptions are pretty much made for this.
class Hello
{
function Test()
{
/** Return the error code if an error was occurred */
if (an_error_occurred)
throw new Exception("An error occurred.");
/** Simulate some simple result. */
return rand(0, 10);
}
}
And when calling it, you'd do this:
try {
$foo = $hello->Test();
}
catch(Exception $e) {
echo "There was a problem: " . $e->getMessage();
}
The code inside the catch block only executes if the exception is thrown inside the Test method. You can create your own exception types to customize this further for different types of errors.
Check it out: http://php.net/manual/en/language.exceptions.php
Should I check if a key exists and then get it or just get it (when I need to get it, not check if its set)?
What is more reliable? safer? faster?
Examples:
1) PHP redis (https://github.com/nicolasff/phpredis)
if ($redis->exists('key'))
echo $redis->get('key');
// VS
if ($value = $redis->get('key'))
echo $value;
2) PHP phalcon cookies(http://docs.phalconphp.com/pt/latest/reference/cookies.html)
if ($this->cookies->has('remember-me'))
echo $this->cookies->get('remember-me')->getValue()
// VS
if ($value = $this->cookies->get('remember-me')->getValue())
echo $value;
Thank you!
My interpretation of this problem is:
I don't like writing things like
if ($value = $redis->get('key'))
echo $value;
it makes code unclear.
Also, why is checking if variable exists so important? Because it simplifies control flow.
Let's consider that you're grabbing some data from service to render it on page. You can write low quality code with multiple ifs, but you can also try something like this:
offerServiceImpl.php
class offerServiceImpl implements offerService {
//... (some methods)
/**
* #param int $offerId
* #return Offer
* #throws InvalidArgumentException
* #throws RuntimeException
*/
public function getOffer($offerId)
{
if (!$offerId || !is_numeric($offerId)) {
throw new InvalidArgumentException("Invalid offer id: " . $offerId);
}
$offer = $this->offerDao->get($offerId);
if (!$offer) {
//could be your own exception class
throw new RuntimeException("Could not found offer " . $offerId);
} else {
return $offer;
}
}
}
offersControler.php
class offersController extends AbstractController{
public function index($id){
//... some code
try{
$offer = $this->offerService->getOffer($id);
} catch (InvalidArgumentException $ex) {
//log error, perform redirect to error 500
} catch (RuntimeException $ex){
//log another error, perform redirect to error 404
} catch (Exception $ex){
//log error, perform redirect to error 500
}
}
}
I have to develop an exception handler that should handle like 5 different type of exceptions. Let's call them simply Ex1, Ex2, Ex3...
I though of doing a single class called ExHandler which will be instantiated like this:
...
} catch (Ex1 $e) { $h = new ExHandler($e); $h->render(); }
catch (Ex2 $e) { $h = new ExHandler($e); $h->render(); }
catch (Ex3 $e) { $h = new ExHandler($e); $h->render(); }
...
And inside ExHandler manage each different Exception differently using $e instance of Ex1, $e instance of Ex2, $e instance of Ex3...
But It doesn't seems a very good practice to me. Is it good? Is there any other way of doing this?
Should I create an Ex1Handler, Ex2Handler, Ex3Handler...? My S.O.L.I.D spirit tells me something is just wrong here. What is it?
I need to note before I answer this, that procedural programmers will look at this and think it's dumb :) but I can live with that, this is assuming an OOP application with HTML templating that outputs after the output_buffer is cleaned.
I always create a try/catch block encompassing the majority of my code in one call usually at the point where I start requiring other files as well as starting an output_buffer whilst in development.
ob_start();
try {
switch($appPage) {
case('work'):
require_once('im_bored_at_work.php');
break;
case('home'):
require_once('im_a_little_less_bored_at_home.php');
break;
default:
require_once('on_the_fence.php');
}
} catch (Exception $e) {
// Handle exception caught and apply formatting
}
$devOut = ob_get_contents();
ob_end_flush();
To give an example how I would handle the multiple exceptions you need to catch with a custom class
class CustomExceptionHandler extends Exception {
private $msg;
private $code;
private $otherVars;
public function __construct($msg,$code=0,$otherDebugVar=null){
$this->msg = $msg != null ? $msg : "An unknown exception was thrown";
$this->code = $code;
$this->otherVars = $otherDebugVar;
parent::__construct($msg,$code);
}
public function getOtherVars() {
return $this->otherVars;
}
}
The idea is to just keep the custom information within the exception object, and when you rethrow the exception at the end of a try/catch block as a standard exception you include the formatted custom message, it shouldn't really matter now which Exception handler picked up the original exception as all the info you will need will come downstream and be caught in the original try / catch block.
class BasicTemplate {
private $template;
private $path;
private $contents;
public function __construct($template, $path) {
$this->template = $template;
$this->path = $path;
$this->buildTemplate();
}
private function buildTemplate() {
if ($contents = #file_get_contents($this->path . $this->template)) {
$this->contents = $contents;
} else {
$e = new CustomExceptionHandler("Message",2,$this->path . $this->template);
// Do whatever else you want to do with custom exception handling class
throw $e;
}
}
}
Now you need to catch your exception and rethrow it:
try {
$html = new BasicTemplate($temp,$path);
} catch {CustomExceptionHandler $e) {
throw new Exception("Message: {$e->getMessage()} Other Info: {$e->getOtherVars()}",$e->getCode());
}
That's the rough idea anyhow, hope it helps.
So I catch an exception (instance of Exception class) and what I want to do is change its exception message.
I can get the exception message like this:
$e->getMessage();
But how to set an exception message? This won't work:
$e->setMessage('hello');
For almost every single case under the sun, you should throw a new Exception with the old Exception attached.
try {
dodgyCode();
}
catch(\Exception $oldException) {
throw new MyException('My extra information', 0, $oldException);
}
Every once in a while though, you do actually need to manipulate an Exception in place, because throwing another Exception isn't actually what you want to do.
A good example of this is in Behat FeatureContext when you want to append additional information in an #AfterStep method. After a step has failed, you may wish to take a screenshot, and then add a message to the output as to where that screenshot can be seen.
So in order to change the message of an Exception where you can just replace it, and you can't throw a new Exception, you can use reflection to brute force the parameters value:
$message = " - My appended message";
$reflectionObject = new \ReflectionObject($exception);
$reflectionObjectProp = $reflectionObject->getProperty('message');
$reflectionObjectProp->setAccessible(true);
$reflectionObjectProp->setValue($exception, $exception->getMessage() . $message);
Here's that example the Behat in context:
/**
* Save screen shot on failure
* #AfterStep
* #param AfterStepScope $scope
*/
public function saveScreenShot(AfterStepScope $scope) {
if (!$scope->getTestResult()->isPassed()) {
try {
$screenshot = $this->getSession()->getScreenshot();
if($screenshot) {
$filename = $this->makeFilenameSafe(
date('YmdHis')."_{$scope->getStep()->getText()}"
);
$filename = "{$filename}.png";
$this->saveReport(
$filename,
$screenshot
);
$result = $scope->getTestResult();
if($result instanceof ExceptionResult && $result->hasException()) {
$exception = $result->getException();
$message = "\nScreenshot saved to {$this->getReportLocation($filename)}";
$reflectionObject = new \ReflectionObject($exception);
$reflectionObjectProp = $reflectionObject->getProperty('message');
$reflectionObjectProp->setAccessible(true);
$reflectionObjectProp->setValue($exception, $exception->getMessage() . $message);
}
}
}
catch(UnsupportedDriverActionException $e) {
// Overly specific catch
// Do nothing
}
}
}
Again, you should never do this if you can avoid it.
Source: My old boss
Just do this, it works I tested it.
<?php
class Exception2 extends Exception{
public function setMessage($message){
$this->message = $message;
}
}
$error = new Exception2('blah');
$error->setMessage('changed');
throw $error;
You can't change Exception message.
You can however determine it's class name and code, and throw a new one, of the same class, with same code, but with different message.
You can extend Exception and use the parent::__construct to set your message. This gets around the fact that you cannot override getMessage().
class MyException extends Exception {
function __construct() {
parent::__construct("something failed or malfunctioned.");
}
}
here a generified snippet i'm using.
foreach ($loop as $key => $value)
{
// foo($value);
thow new Special_Exception('error found')
}
catch (Exception $e)
{
$exception_type = get_class($e);
throw new $exception_type("error in $key :: " . $e->getMessage());
}
An ugly hack if you don't know which kind of exception you're handling (that can have its own properties) is to use reflection.
try {
// business code
} catch (\Exception $exception) {
$reflectedObject = new \ReflectionClass(get_class($exception));
$property = $reflectedObject->getProperty('message');
$property->setAccessible(true);
$property->setValue($exception, "new message");
$property->setAccessible(false);
throw $exception;
}
You should use this crap wisely in very specific case when you don't have any other choice.
You can't change the message given by the Exception class. If you wanted a custom message, you would need to check the error code using $e->getCode() and create your own message.
If you really wanted to do this (in the only situation I can think that you might want to do it), you could re-throw the exception:
function throwException() {
throw new Exception( 'Original' );
}
function rethrowException() {
try {
throwException();
} catch( Exception $e ) {
throw new Exception( 'Rethrow - ' . $e->getMessage() );
}
}
try {
rethrowException();
} catch( Exception $e ) {
echo $e->getMessage();
}
The php Exception class has a __toString() method which is the only method within the Exception class that is not final, meaning it can be customised.
class HelloMessage extends Exception {
function __toString() {
return $this->getMessage()." you have an error with code: ".$this->getCode();
}
}
You use it as follows within try-catch block:
try {
if (2 > 0) {
throw new HelloMessage("Hello", 10);
}
} catch (HelloMessage $e) {
echo $e;
}
Output would be:
Hello you have an error with code: 10
You can extend Exception with your own, and put a setter in it
class MyException extends Exception
{
private $myMessage = '';
public function getMessage()
{
if ($this->myMessage === '') {
return parent::getMessage();
} else {
return $this->myMessage;
}
public function setMessage($msg)
{
$this->myMessage = $msg;
}
}
This is an improved version of David Chan's answer. It's a re-throw solution which uses get_class to rethrow the same exception type, and it passes all parameters to the constructor, even in the case of ErrorException, which has six rather than three constructor parameters.
foreach ($loopvar as $key => $value)
{
doSomethingThatMightThrow($value);
}
catch (\Exception $e)
{
$exception_type = get_class($e);
$new_message = "[key '" . $key . "'] " . $e->getMessage();
if ($e instanceof \ErrorException) {
throw new $exception_type($new_message, $e->getCode(), $e->getSeverity(), $e->getFile(), $e->getLine(), $e);
}
throw new $exception_type($new_message, $e->getCode(), $e);
}
What are best way of error handling? This is what I came up with:
class test {
public static function Payment($orderid, $total) {
if (empty($orderid) && empty($total)) {
return array('status' => 'fail', 'error' => 'Missing Data');
}
}
}
I heard about Try/Exceptions but how to fit that into my code? If you could provide example that would be great!
If you use PHP 5, you can handle error with exception :
http://fr2.php.net/manual/en/class.exception.php
This way is cleaner than manual set exception message, because you have access to a try catch system and you can isolate exception handling
As mentioned, use Exceptions. Specific to your example, you throw an exception if some condition fails. Then when you envoke the method that can throw an exception, you wrap it with a try/catch handling block.
class test {
public static function Payment( $orderid, $total ) {
if (empty( $orderid ) && empty( $total )) {
throw new Exception('Missing Data');
}
}
}
try {
test::Payment("1", "2"); //should be fine
test::Payment(); //should throw exception
} catch (Exception $e){
echo $e;
//do other things if you need
}
You could use exceptions.
However, in the use case you've posted, simply doing the checks at the controller level should suffice.
I also think that explicitly checking the return type for array (on fail) is counter intuitive.
Here is how you might modify your code to use an exception. It also helps to document the circumstances under which the exception is thrown.
class test {
/**
* [method description]
* #throws Exception if the order ID or total is empty
*/
public static function Payment($orderid, $total) {
if (empty($orderid) && empty($total)) {
throw new Exception("fail: Missing Data");
}
}
}
You can also create your own exception class if you want to include extra data in the exception.
class MyException extends Exception{
public $status, $error;
public function __construct($status, $error){
parent::__construct("$status: $error");
$this->status = $status;
$this->error = $error;
}
}
I tend to lean towards throwing exceptions, and then using the try/catch mechanism to deal with the aftermath. The man page is here: http://php.net/manual/en/language.exceptions.php
The best practice is to use Exceptions.
http://php.net/manual/en/language.exceptions.php