Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

freel's avatar

Exception handling

I have problem with error handling. Please see code bellow. When exception is thrown I want to stop code, because like now I am getting error message as well I am returning success result and $billing->givepoints() executing.

How to check in controller is any error returning my method charge or stop executing code if error returning.

<?php
/**
 * Created by PhpStorm.
 * User: Freel
 * Date: 09/05/16
 * Time: 06:55
 */

namespace Acme\Billing;

use Exception;
use Stripe\Stripe;
use Illuminate\Support\Facades\Config;


class StripeBilling implements BillingInterface {


    // Function
        public function __construct(){

            Stripe::setApiKey(Config::get('stripe.secret_key'));
        }

        public function charge(array $data){
            try{
                return \Stripe\Charge::Create([
                    'amount'        => $data['amount'],
                    'currency'      => 'gbp',
                    'description'   => $data['description'],
                    'customer'          => $data['customer']
                ]);


            } catch (\Stripe\Error\RateLimit $e) {

                return redirect()->back()->with('danger','Too many requests made to the API too quickly');

            } catch (\Stripe\Error\InvalidRequest $e) {

                return redirect()->back()->with('danger','Invalid parameters were supplied to Stripe\'s API');


            } catch (\Stripe\Error\Authentication $e) {


                return redirect()->back()->with('danger','Authentication with Stripe\'s API failed (maybe you changed API keys recently)');

                // (maybe you changed API keys recently)
            } catch (\Stripe\Error\ApiConnection $e) {
                return redirect()->back()->with('danger','Network communication with Stripe failed');

            } catch (\Stripe\Error\Base $e) {
                return redirect()->back()->with('danger','Error: '.$e->getMessage());

                // Display a very generic error to the user, and maybe send
                // yourself an email
            }catch(Exception $e) {
                return redirect()->back()->with('danger','Error: '.$e->getMessage());

                // Something else happened, completely unrelated to Stripe
            }


        }
}
class PaymentController extends Controller{
// Function Buy items
        public function Buy(Request $request){
            $billing = \App::make('Acme\Billing\BillingInterface');
            $result = $billing->charge([
                'amount'        => $request->packages*1000,
                'description'   => Auth::user()->email,
                'customer'          => $request->customer
            ]);
    $billing->givepoints(); 
            return redirect()->back()->with('success', 'Payment done succesiful.');
        }
}

thx a lot for help.

0 likes
9 replies
ohffs's avatar

In your current code you'd have to check what $result is (eg, if ($result instanceof whatever-redirect()-classname-gives) { return $result; }. You might be better returning an error message or true from the charge() method though - then you can do something like if ($result !== true) { return redirect()->back()->with('danger', $result); } which would save you a lot of replicated code.

freel's avatar

well I was thinking about returning true. but I will need to access values from $result, So If I will return true I will lose this value. Isn't?

I was thinking maybe we have some function in php something like

if (has_exepction($result)) {
    return 'ERROR';
}else{
    return 'DONE';
}

I am talking about controller;

ohffs's avatar

Why not move the try/catch to the controller? Then you can just do :

try {
  $result = $billing->charge([
                'amount'        => $request->packages*1000,
                'description'   => Auth::user()->email,
                'customer'          => $request->customer
    ]);
} 
catch (\Stripe\Error\RateLimit $e) {
                return redirect()->back()->with('danger','Too many requests made to the API too quickly');
} .... etc

Or check the $result is an instance of whatever \Stripe\Charge::Create gives you rather than true. Or many other ways ;-)

jimmck's avatar
jimmck
Best Answer
Level 13

@freel You need to take advantage of the full Exception handling pattern.

try {
    ...some code
catch (Exception-Type $e) {
    ... handle Exception
} catch (Another Exception-Type $e) {
} finally {
    ... return some value or error
}

Regardless of if an Exception is thrown or the code in the initial try block succeeds the finally block will execute.

So for example:

class CreateCvgCategory extends DbCommand implements IDbCommand
{
    public function exec($shortName, $longName)
    {
        $ret = null;
        try {
            $this->doThrow();
            $m = new CoverageCat($this->sql); // Call Model.
            $ret = $m->create($shortName, $longName);
            $ret = new Message($ret, Message::STATUS_OK, 402);   // Record created message.
        } catch (InvalidArgException $e) {
            $ret = $e;
        } catch (DBConnectionException $e) {
            $ret = $e;
        } catch (SQLException $e) {
            $ret = $e;
        } catch (\Exception $e) {
            $ret = $e;
        } finally {
            $this->close();

            return $ret;
        }
    }
}
freel's avatar

@jimmck trying to understand your code. I like main idea because its out of my controller. Sorry for stupid question, but New Message class u have your own class for sending messages or u using php/laravel class. Can understand that :)

jimmck's avatar

@freel Yes basically I keep things as real PHP objects for the most part. My own system has 3 types: Data messages, Messages (Flash type) and Exceptions. All of the messages get assembled by the controller. They only dispatch requests and format replies. The Command objects actually carry out the work. This way they can be called by API's for external backend consumers.

So the Controller looks like this. It has a custom class which parses all browser requests. Everything is sent/received as JSON objects. The browser updates the page based on the objects. Data is passed to Vue components. Messages and Exceptions and handled by Alertify.js .

The Command code works as is in Zend or Laravel. For the controller I use Caffinnated Modules package to split tenants.

<?php namespace App\Modules\Coverage\Http\Controllers;

use App\lib\myutils\dbutils\datamaps\DataMap;
use App\lib\myutils\apputils\Payload;
use App\lib\myutils\utils\Utils;
use App\Modules\Coverage\Commands\GetAllCvgCategories;
use App\Modules\Coverage\Commands\GetCvgCategory;
use App\Modules\Coverage\Commands\CreateCvgCategory;
use App\Modules\Coverage\Commands\UpdateCvgCategory;
use App\lib\myutils\apputils\cmdinput\CommandExec;
use App\Modules\Coverage\utilobjects\cmdinputs\CreateInputs;
use App\Modules\Coverage\utilobjects\cmdinputs\FindInputs;
use App\Modules\Coverage\utilobjects\cmdinputs\UpdateInputs;
use App\Http\Controllers\Controller;
use App\lib\myutils\apputils\MsgException;
//use Mail;

class CoverageCtrl extends Controller
{
    use CommandExec;

    /**
     * Display a listing of the resource.
     *
     * @return Payload
     */
    public function index()
    {
        if ($this->ping()) {
            return "";
        }

        return $this->cmdExec(null, $_POST, 'execIndex', 'Load Records');
    }

    public function execIndex()
    {
        $cmd = new GetAllCvgCategories();

        return $cmd->exec();
    }

    /**
     * Creates a new record.
     *
     * @return Response
     */
    public function create()
    {
        if ($this->ping()) {
            return "";
        }
        $in = new CreateInputs();

        return $this->cmdExec($in, $_POST, 'execCreate', 'Create Entry');
    }

    public function execCreate($in)
    {
        $cmd = new CreateCvgCategory();

        return $cmd->exec($in->shortName, $in->longName);
    }

    public function execUpdate($in)
    {
        $cmd = new UpdateCvgCategory();
        //$in->setShortName('LIS!');
        $shortName = $in->getShortName();

        return $cmd->exec($in->id, $shortName, $in->longName);
    }

    public function update()
    {
        if ($this->ping()) {
            return "";
        }
        $in = new UpdateInputs();

        return $this->cmdExec($in, $_POST, 'execUpdate', 'UpDate Entry');
    }

    public function execFind($in)
    {
/*
        Mail::raw("Testing", function ($message) {
            $message->to('[email protected]', 'Jim')
              ->subject('LaravelGMail App!');
        });
        */
        $cmd = new GetCvgCategory();
        $ret = $cmd->exec($in->id);

        return $ret;

        //return "Sent...";
    }

    public function find()
    {
        if ($this->ping()) {
            return "";
        }
        $in = new FindInputs();

        return $this->cmdExec($in, $_POST, 'execFind', 'Find Entry');
    }
}
freel's avatar

I am really like way you writing your code and how it looks. Thats exactly what I am trying to achieve. As you probably you understand I still learning how to make it (keep code in peaces) and so on.

Why you need 3 types?

My own system has 3 types: Data messages, Messages (Flash type) and Exceptions. 

so this code below is one of your message type.

 $ret = new Message($ret, Message::STATUS_OK, 402);   

I think way you working with messages is "high-end" for me. I will try to play few more hours if will be no result I will go back to @ohffs solution ;)

Thank you guys!

freel's avatar

easiest solution i find out is check is value we getting back is object.

//my controller
// Function Buy items
        public function Buy(Request $request){

            $billing = \App::make('Acme\Billing\BillingInterface');


            $ret = $billing->charge([

                'amount'        => $request->packages*1000,
                'description'   => Auth::user()->email,
                'customer'          => $request->customer
            ]);



            if (is_object($ret)){

               return redirect()->back()->with('success', 'Giving points');
            }else{

                return redirect()->back()->with('danger', $ret);
            }


        }

//my class
public function charge(array $data){

            try{
                return  \Stripe\Charge::Create([
                    'amount'        => $data['amount'],
                    'currency'      => 'gbp',
                    'description'   => $data['description'],
                    'customer'          => $data['customer']
                ]);


            } catch (\Stripe\Error\RateLimit $e) {

                return 'Too many requests made to the API too quickly';

            } catch (\Stripe\Error\InvalidRequest $e) {

                return 'Invalid parameters were supplied to Stripe\'s API';



            } catch (\Stripe\Error\Authentication $e) {


                return 'Authentication with Stripe\'s API failed (maybe you changed API keys recently)';

                // (maybe you changed API keys recently)
            } catch (\Stripe\Error\ApiConnection $e) {
                return 'Network communication with Stripe failed';

            } catch (\Stripe\Error\Base $e) {
                return $e->getMessage();

                // Display a very generic error to the user, and maybe send
                // yourself an email
            }catch(Exception $e) {
                return $e->getMessage();

                // Something else happened, completely unrelated to Stripe
            }


        }

Please or to participate in this conversation.