What do you think is the best way to catch all doctrine 1.2 ORM exceptions in codeigniter framework, i would not like to wrap the entire index.php with a try catch, but neither to do a try catch before and after every query,
Well, first, you'll have to wrap around only single line in index.php. And actually, this might be good in case you have exceptions you don't want to show (e.g. in production environment).
The second point here is that your database-related code should be concentrated in models. So you might introduce helper class, which is something like
class SafeQueryHelper{
public static function safeQueryRun(Doctrine_Query $q, array $parameters, $hydration=Doctrine_Core::HYDRATE_RECORD){
try{
return $q->execute($parameters, $hydration);
}
catch(Exception $e){
//Handle yur exceptions here
}
}
}
Than you'll just replace $query->execute($params,$hydration) in all your models to SafeQueryHelper::safeQueryRun($query,$params,$hydration). Don't forget to load it with $this->load->helper('SafeQueryHelper') or through the config.
For record methods like update and delete - you'll have to wrap it in try .. catch.
Well, and if you don't have your database-related logic concentrated in models... That changes nothing, actually, but that means that you have poorly-designed application that violates the essential priinciple of MVC pattern, so start refactoring.
The last possible solution - is to hack into Doctrine core classes (specifically into Doctrine_Connection) and wrap into try ... catch lines that perfrom actual quering. But that's a bad idea, I really wouldn't do that.
A little update: as all Doctrine entity objects are subclaeses of Doctine_Record youmay extend SafeQueryHelper with methods for wrapping save, delete etc:
public static function SafeSave(Doctrine_Record $entity){
try{
$entity->save();
}
catch(Exception $e){
//catch it
}
}
Than replace $entity->save() with SafeQueryHelper::SafeSave($entity)
Related
A basic use case would be calling MyEventListener::class without having imported use MyNamespace\MyEventListener. The result would be a broken piece of code that's relatively hard to debug.
Does PHP 7 provide a directive to crash instead of returning the class name if no class exists? For example:
After calling use Foo\Bar;, Bar::class would return 'Foo\Bar'.
But if no import statement, PHP returns 'Bar', even though the class doesn't exist, not even in the global namespace.
Can I make it crash somehow?
The thing you need to keep in mind is that use Foo\Bar; is not "importing" anything. It is telling the compiler: when I say "Bar" I mean Bar from the namespace Foo.
Bar::class is substituted blindly with the string "Foo\Bar". It isn't checking anything.
Until you attempt to instantiate or interact with a class it will not check to see if it exists. That said, it does not throw an Exception, it throws an Error:
// this doesn't exist!
use Foo/Bar;
try {
$instanceOfBar = new Bar();
}
catch (Error $e) {
// catching an Exception will not work
// Throwable or Error will work
}
You can trap and check for non-existent classes at run time, but until you do it will happily toss around strings referring to classes that don't exist.
This is a blessing in the case of Laravel's IoC container and autoloader that abuses this to alias classes as convenient top-level objects. A curse, if you were expecting PHP to throw a fuss on ::class not existing.
Update:
My suggestion for anyone worried about this problem is to use PHPStan in your testing pipeline. It prevents a lot of mistakes, and unlike php -l it will catch if you were to try and interact with a non-existent class.
As far as I know you're going to get a nice error message when you try to instantiate a class that cannot be found through autoloading or explicitly added.
If you want to check if the class exists, first, try this:
$classOutsideNamespaceExists = class_exists('Bar');
$classInsideNameSpaceExists = class_exists('\\Foo\\Bar'));
Or you could try this syntax available since PHP 5.5:
class_exists(MyClass::class)
Finally, you can always use the tried and true method of a try-catch block.
try {
$instanceOfMyClass = new MyClass();
}
catch (Exception $e) {
// conclude the class does not exist and handle accordingly
}
PhpStorm proposes and generates hints like ArrayShape, Pure, etc.
But automatically it is adding
php use JetBrains\PhpStorm\ArrayShape;
or another.
Is not that dangerous that on some production server I will get error
'Class JetBrains\PhpStorm\ArrayShape not found'?
(c)LazyOne:
Well, just use composer require --dev jetbrains/phpstorm-attributes to add such classes to your project. See github.com/JetBrains/phpstorm-attributes
As long as instance of such a class is not actually gets instantiated (created) you should have no error because use statement is just a declaration.
Now what I generally do when writing code is something like this
function changeBookAuthor(int $id, string $newName){
if(!$newName){
throw new MyAppException('No author name was provided');
}
$book = Books::find($id);
if(!$book){
throw new MyAppException('The provided book id could not be found');
}
}
in the laravel doc we see:
https://laravel.com/docs/5.4/errors
public function report(Exception $exception)
{
if ($exception instanceof CustomException) {
//
}
return parent::report($exception);
}
Now how to I properly handle the exception? they are all the same exception and they have no code neither. Should I provide an error code?
the problem with php exception is that they use integers. Is quite annoying imho. Better would be 'changeauthor_bookid_notfound' as code instead of a random number. Should I create an exception class for each single exception? e.g. not reuse MyAppException that seems a bit tedious. I would have a trillion classes.
Now if for a special exception I want special handling, with my code, I cannot easily do it. I have no code to check for (e.g. $exception->code == 3331 then do special) and I don't have custom exception classes neither
what is a proven good solid way to handle this case?
code, new class on each error, something else all together?
and if provide a code, what is a nice way to do it?
The "proper" way to do it would be to define either a custom Exception class for each exception, or to define custom exceptions based on the type of error being thrown, however realize that Laravel already has many built in exceptions and mechanics for handling the use cases you outlined.
For instance, in the case of the "Book Not Found" exception, rather than manually triggering an exception yourself, you could use Books::findOrFail($id); which throws an instance of ModelNotFoundException when appropriate.
Also, in PHP there is no need to handle exceptions for unprovided arguments. Unless expressly denoted as optional, all method arguments are required, and Laravel will throw a PHP exception if an argument is missing.
Additionally, Laravel provides the abort() magic method which throws a HTTP error along with a custom error message and can be used like so:
abort(418, "I'm a teapot...")
So, if you must reinvent the wheel, the proper way is to define custom exception classes and define the custom handlers for those classes, but realize that Laravel already has many built in tools for managing exceptions without needing to do so.
I have a class that receives some initialization values in its constructor and uses them to implement an interface. My code creates several objects from this class, with different initialization values.
Whenever an exception occurs in one of the methods, the stacktrace shows which class and method threw the exception, but not which object did.
Therefore, I would like to wrap every exception that leaves my class with some additional information, including the original initialization values that object received in its constructor. This should happen both to exceptions that I throw myself (that's trivial) and to ones thrown by the runtime (such as NPEs) and by libraries used by my class.
Of course, I could wrap every public method in a try/catch:
public function whatever(...)
{
try {
// ...
} catch (\Throwable $e) {
throw $this->wrapException($e);
}
}
But adding those 4 lines to every public method and indenting the body of every method one level, just to get more readable stacktraces, violates the DRY principle and is plain ugly.
Is there a better way? A generic OOP design pattern or maybe some PHP-specific trick that can address this issue, such as magic method names?
I am useing a class in my code from the base framework. But it might not be available yet:
use BaseFramework\Libs\SpecialException;
So this use-Statement will result in an error. I.e. for frameworks, where this SpecialException is not available I would like to do:
use Exception as SpecialException;
so that I do not need to change my code.
I learned that the use is only creating an alias to the full named class.
I would like to use the originial SpecialException, if this is not possible I would like to use Exception.
I am wondering, what is the best practice or recommended way in PHP to solve this?
You can decide which one to throw using class_exists, it's going to be pretty nasty to actually use though.
Example:
try {
// do something
} catch (\Exception $e) {
// you'd still need to catch a common exception to all your custom types
if (class_exists('SomeCustomException')) {
throw new SomeCustomException; // or whatever
}
}
But you'd need to do that or something equally awful everywhere.
Your question suggests the actual answer here is to implement your own custom exception and throw that instead, as you have full control over it then.
Sometimes frameworks get around this kind of issue by having shared interoperability packages, so they can conform to common interfaces, throw the same exceptions and so on.
Since SpecialException might contains methods, variables and stuff that Exception doesn't contain, there is no rock-solid way to achieve what you need. Just replacing a class with a more generic one, might lead to trouble once you use some of the more dedicated methods.
You can see this post for working with class-aliases to achieve your desired behaviour, but for the reason meantioned above I wouldn't recommend it:
Why use class alisases?
You rather should use the factory-Pattern, just import the super-type of your eventually-custom-class and work with that super-type.
As soon, as you need to call a method on an instance, where you are not sure if that method is present (due to up-casting) - your class definition (or at least the method required) is placed into the wrong level inside the inheritance tree.
OK, thanks to some clues by #dognose and #bcmcfc this works for me:
use BaseFramework\Libs\SpecialException;
if (!class_exists("SpecialException")) {
class_alias("Exception", "SpecialException");
}
Why not just extend Exception? Something like this ...
namespace ProjectName\Exceptions\SpecialException;
class SpecialException extends Exception
{
// Implement custom properties and methods if required. Optional.
}
Here we have a custom class that uses SpecialException:
use \ProjectName\Exceptions\SpecialException;
class DocumentRepository
{
public static function fetchByID($docID)
{
throw new SpecialException("Document does not exist");
}
}
And now you don't need to worry about whether or not SpecialException exists or not. If calling code throws a regular Exception it will get caught, but if it throws a SpecialException it will still get caught as the new exceptions base class is Exception.
try
{
$doc = DocumentRepository::fetchByID(12);
}
catch(Exception $e)
{
die($e->getMessage());
}
Or, if you want to catch the SpecialException you can do (and I highly recommend this):
try
{
$doc = DocumentRepository::fetchByID(12);
}
catch(SpecialException $e)
{
die($e->getMessage());
}
Update to answer the problem in your comment
As a developer using a framework you have a location where you store your custom classes, files etc. right? Let me assume that this location is ProjectName/lib. And lets assume the framework you're using lives in the directory ProjectName/BaseFramework.
Your custom SpecialException will live in ProjectName/lib/Exceptions/SpecialException.php.
Currently, the framework doesn't include this exception. So in the files you wish to use SpecialException you use the following use line:
use \ProjectName\Exceptions\SpecialException
When the framework finally does implement this SpecialException you simply replace that use line with this one:
use \BaseProject\Exceptions\SpecialException
It's as simple as that.
If you try to do this in the way other users have suggested you will have dead code in your system. When SpecialException is finally implemented the checks on which type of Exception to use will be redundant.
This assumes you're using something like composer or something else that handles autoloading.
Recently I have been developing in Zend Framework. I came into a confusion during exception handling.
Can anybody let me know where is the best place to handle exception? Whether it is model or controller? It may be in terms of performance or usability or anything else.
If we want to catch all kinds of exceptions, we better enable our model to throws exception. You can read this post also link
You should handle exceptions in your controllers because sometimes the error messages of exceptions should be passed on to views. To avoid the dependency between models and views you should handle exceptions in your controllers.
Zend Framework all ready handles exceptions through the inbuilt errorController. You can enable it by placing the following line in your config file.
resources.frontController.throwExceptions = 0
Also, if you want to handle exceptions your self, rather then handling them at different places you can just handle them at one place. Something like below.
Tell Zend Framework to not handle exceptions. Do this in your application.ini
resources.frontController.throwExceptions = 1
Do following in your Bootstrap class.
Define a custom method to handle exceptions.
public function __handleExceptions(Exception $e){
//render a view with a simple error message for the user
//and send an email with the error to admin
}
Override the _bootstrap() and run() methods of Zend_Application_Bootstrap_Bootstrap in your Bootstrap class and catch the exceptions thrown during the bootstrap process or while running the application and call your exception handler as shown below.
protected function _bootstrap($resource = null)
{
try {
parent::_bootstrap($resource);
} catch(Exception $e) {
$this->__handleExecptions($e);
}
}
public function run()
{
try {
parent::run();
} catch(Exception $e) {
$this->__handleExecptions($e);
}
}
Now all your exceptions will be handled from a single place.