Appropriate use of exceptions? - php

We are developing a collection class for a specialized PHP application. In it, there are functions named map, each, etc.
A debate has been brought up about calling some functions with a bad argument. For example:
public function each($fn) {
// ...
}
// ...
$collection->each('not a function');
Should the call to each throw an exception? Should it return null? Should we ignore the bad argument and let the runtime error when an attempt is made to call the nonexistant function? I'm not sure how we should handle this case.

exceptions are for exceptional situations, not bad coders.
Use assertions instead.
See http://php.net/manual/en/function.assert.php
If this is for a library for external use, then exceptions on exposed methods may make sense, (e.g. InvalidArgumentException) but, in general, assertions are more appropriate for verifying internally that your code meets your required conditions.
Perhaps another example will help clarify things, a good use of an exception is when doing file access and as there is some possibility that the resource will not be accessible due to a downed server, etc.
Also see Design by contract using assertions or exceptions?

Related

PHPUnit-testing with anonymous functions

Say I use a framework like Slim (PHP) and I have this pretty modern code structure:
$app->post("/", function($request, $response) {
// define the post actions here
});
I could put the anonymous function into a separete class, but is there a way to write a test without loosing this code structure?
Thank you.
there are some ways to test that. Regardless, I would recommend splitting each handler into it's own file (probably even a class, that has an __invoke method). The reason is that this way of defining handlers looks short and crisp now. But once you have more than 10 endpoints it gets really ugly to maintain and you're mixing routing logic together with different handlers.
If this is a very small project and you want to keep that kind of syntax, there are two strategies to test it. But be aware that both of them are going to be a bit more cumbersome than you might like:
Integration Test Style (NOT recommended)
you just call $slim->run() in your tests and check if the output of the handler fits your expectations. Slim offers a nice way to mock a http request as you can find at the bottom of that page. Please be aware that you'll be limited to only check on the data that is returned from your handler. If your handler returns plain HTML, you can only check that the html returned contains the right things.
You could take this a bit further if you used slim's dependency injection feature and provided mocks to it.
Simple Handler Style (recommended)
Alternatively you can also keep your anonymous handler function in the routing but defer the handling of the actual business logic to another class, which you could then test. If your controller is very simple and does nothing but retrieve GET/POST parameters and forward them to a class, then there's not such a lot of testing to it.
Besides this giving you an angle to test, it's also a nicer way to think about seperation of concerns. Your slim handler function will take care of framework and HTTP basics, and you'll have a nice domain class that does not need to bother with this.
$app->post("/register", function() {
$result = (new RegisterUserAction())
->register($_POST["email"], $_POST["password1"], $_POST["password2"]);
// now use $result to render the html page to show to the user
});
If you want to test exactly this anonymous function, you can try to mock an $app variable:
$app = $this->getMockBuilder('app class')->disableOriginalConstructor()
->setMethods(['post'])
->getMock();
$app->method('post')->willReturnCallback(function ($url, $anonymousFunction) {
// do some tests with $anonymousFunction
});

PHPUnit using annotations to assert exception vs method call

There are two ways to assert the exception in Phpunit:
using annotation #expectedException
using method call $this->expectException()
I've tried both of them, they work fine and exactly the same.
Which is the correct way?
Are there any guidelines on which one should be used?
PS: When the exception is based on some condition and does not always happen then obviously the method should be used.
Using expectException() is considered best practice, see this article.
There's a few clear advantages for me on why I'd choose to use the method rather than the annotation.
In the annotation form, you have to use the full namespace to the class name for it to work:
#expectedException MyException // Not found unless it is within the current namespace
#expectedException \Some\Deep\Namespace\MyException // works
The alternative:
$this->expectException(MyException::class); // works, with a 'use' statement
This is more readable, more explicit, flexible (automated refactoring/renaming would be a doddle in most editors like PHPStorm), is less code to write, and is in line with the standard test method setup of the 3 phases in correct order, Arrange, Assert, Act. Lastly, the annotation internally would need to be parsed, and would only call the expectException method anyway. So it's going to be more efficient as well.

Class throwing exceptions for anything other than success, is it a good practice/programming form?

I'm writing some classes and would like to know how to properly handle scenarios which are not success. For example, a file upload class, which as a parameter accepts the name of $_FILES resource:
class FileUpload {
private $file;
public function __construct($file) {
$this->file = $file;
}
public function upload() {
if (!isset($_FILES[$this->file])) {
throw new Exception("Reference to non existent resource.");
}
if ($_FILES[$this->file]['error'] !== 0) {
throw new Exception("Resource indicates error.");
}
// All other sorts of checks here, like security checks,
// and then finally moving of the file to it's final destination
}
}
Is this proper form? My line of thinking is this: when a developer creates a new instance of FileUpload, his intention is either have the file uploaded, or know why it wasn't uploaded, and this class will give him just that. Either:
1) true (file was tested for proper format, security checked, maybe even further processed if it was an image, and now it is exactly where you want it to be. In short - everything you wanted worked out)
2) Exception (Something went wrong, and the message is letting you know exactly what, so you can deal with it.)
IF all this is fine, should I just use Exception, with custom messages, or create custom exceptions for everything, for example WrongMimeType?
If it matters - classes would be open source, available for everyone to use, so from that aspect too I'd like to make them as standardized, developer-friendly and easily plugged into existing software as possible.
This should probably be moved to codereview because it looks to me like a question about coding style.
However:
Your upload() method is badly designed. It should accept a parameter, not grab the data from $_FILES - the outside user should pass it into the function. No class should generally grab data from a superglobal or global variable.
Honouring that dismisses the first reason to throw an exception. :)
And then? It's kind of hard to discuss details further because there isn't really much code to see, so I fall back to the general remarks:
Exceptions should NOT be used as a replacement for goto. They should signal exceptional state that could not be anticipated.
When validating a form, invalid form data is no exceptional state that cannot be anticipated - it is one of two usual cases. Effectively you are validating the form data in your class - you shouldn't throw exceptions if the form is not valid.
Another thing: Do not hide the thing that went wrong in the exception message. It makes it so much harder to use the class if I cannot catch the different exception classes thrown with multiple catch statements, but would have to look at the messages.
And because you are asking about making that code usable to others: Use namespaces, PSR-0 compatible autoloading and your own exception classes. And do not grab data from superglobals.

PHP_CodeSniffer Many Classes per file sniff

We have a standard in use, where we create exceptions within the main class for returning errors etc... The problem is, that all the standard sniffs do not like this. We are writing our own sniffs then for this, but thought I would inquire why this was not desirable?
For instance, we have:
<?php
class FOO_EXCEPTION extends Exception { }
class FOO_EXCEPTION_BAR extends FOO_EXCEPTION { }
class FOO_EXCEPTION_POLE extends FOO_EXCEPTION { }
class FOO
{
public function MethodDoingSomething()
{
if('some condition happens') {
throw new FOO_EXCEPTION_BAR();
}
if('some other condition') {
throw new FOO_EXCEPTION_POLE();
}
...
}
}
?>
This allows our code to return different exceptions to indicate what happened to the caller, but if a dedicated try/catch is not available, the basic Exception may still be caught.
This comes in handy when working with databases or other external objects, since the nature of the error may be returned to a component higher up the call stack to handle the error.
For instance, if you are deleting a file, and the file does not exist, the code may throw the exception, but the caller has the option to ignore this if it was not concerned that the file did not exist, since it was trying to delete it anyhow. However, another caller, could error out with the absence of a file that was suppose to exist when it was being deleted.
In my opinion, the coding standard which you describe in your question is perfectly reasonable. And I think for the purposes of your project it would be better to tweak the "standard multiple classes per file" sniff so that it works with your code in this particular (special) case rather than waste your time tweaking your codebase to comply with "the letter of the law" for this particular sniff.
I agree with the assertion that it is better in general to avoid putting multiple class definitions in a single file. But every argument I've read (so far) for moving each and every Exception-derived class into its own separate file strikes me as an exhortation to "improve" code by making it less readable. As a human, I gain no maintainability benefit from cluttering my code with files containing a single line, each.
It's true that it is easier to write an autoloader, for example, if each class lives in its own file. And if you're generating/compiling your PHP code from some sort of meta-language then it costs you nothing to add extra levels to your directory structure. But I reject the conclusion that this way of organizing the code actually improves it in any useful-to-humans way.
EDIT:
For the record, I can see that it would be a good idea to move the definition of an Exception-derived class into its own file if it actually contains some "testable" logic. In such cases you might need to mock/stub the class when writing automated tests for the logic which uses the class, which would require you to be able to load the class definition separately from the logic which uses it. But this not the situation described in the original question, where the Exception-derived classes are all "empty".

suggestions for unit testing exceptions

Consider a method which might throw an exception with some descriptive text:
if ($someCondition) {
throw new \Whatever\Exception('dilithium exhausted');
}
And elsewhere in the method is another block that might throw the same exception, but with different text:
if ($anotherCondition) {
throw new \Whatever\Exception('differentialator exploded');
}
While writing unit tests for this class, you create failure cases so that you can verify that these two exceptions get thrown properly. In these failure cases, do you prefer to:
A) Use #exceptionExpected in the test method's docblock to trap the generic \Whatever\Exception class and subsequently ignore the getMessage() text, assuming you got the right one? (Seems like a bad idea.)
or:
B) Use try/catch and then assert that the caught exception's getMessage() text equals the exact descriptive string you're expecting? (More resilient but it means changing your tests whenever you change your error wording.)
or:
C) Create a separate exception for each error case (e.g., \Whatever\DilithiumException and \Whatever\DifferentialatorException) and then use #exceptionExpected for each one.
I'm currently using B but tending toward C. I'm curious what others are doing in this same scenario. Do you have any guidelines that help you determine, "At what point does an error deserve its own exception class versus a more generic shared one?"
All of the above.
A is great, and I use as much as possible because it is simplest. There is another case when A does not work:
/**
* #exceptionExpected FooException
*/
test() {
// code that could throw FooException
...
// purpose of the test that throws of FooException
}
In this case, the test could pass when it should have failed because it didn't even get to what I was testing. A good way to deal with this is to use $this->setExpectedException()
B is great when you might actually use information from the exception. Rather than using the text of the exception message I would prefer to use the code. I have a form validation exception that packages up all the problems encountered in the data into one exception. By extending the exception class it becomes easy to transmit a good deal of information from the internal error state to the external handling code.
C accomplishes the same thing as B, but allows for simplifying the code by relying on more classes. The difference between these two is subtle and I tend to rely on design aesthetic to make the decision.
TL; DR: Use exception codes rather than messages, and design to the use case rather than the unit tests.
PHPUnit also provides #expectedExceptionCode and #expectedExceptionMessage when you need this level of detail. Warning: The latter requires the former.
BTW, I also tend toward A. If I need to express more meaning in the exception, I prefer to create a new exception class. I find the message to be too volatile to be worth testing in most applications.

Categories