4

Which structure of writing code is better and why?

if (!file_exists('file.txt')) {
   throw new Exception();
} else {
   //operations
}

or

if (!file_exists('file.txt')) {
   throw new Exception();
} 
//operations

?

I did not find this in PSR documentation.

nubakusev
  • 53
  • 2
  • Possible duplicate of [How would you know if you've written readable and easily maintainable code?](https://softwareengineering.stackexchange.com/questions/141005/how-would-you-know-if-youve-written-readable-and-easily-maintainable-code) – gnat May 13 '17 at 14:22
  • 1
    If the existence of the file is a pre-condition for a lengthy operation, the second option is cleaner. You will have the pre-condition "out of the way" and the reader will not have to think sbout it anymore, it will not be part of the logic that follows. If it were more of a case of doing "one or the other" and either action would be equally short, the first option would be better, stressing the fact that the condition determines which of the two possible actions is to be performed. – Martin Maat May 13 '17 at 15:12

2 Answers2

13

What your describing in your second code example is a Guard Clause.

Guard clauses exist to help you avoid excessive nesting of conditions, which are hard to maintain and difficult to read:

if ()
{
    throw;
}
else
{
    if()
    {
        return;
    }
    else
    {  
         if()
         {
             log and return;
         }
         else

Writing guard clauses allows you to keep your conditions separated:

if()
{
    throw;
}

if()
{
    return;
}

if()
{
    log and return;
}

// Do actual work

Each guard clause can identify a specific condition or do specific cleanup work prior to exiting the function.

Further Reading
Replace Nested Conditional with Guard Clauses

Robert Harvey
  • 198,589
  • 55
  • 464
  • 673
  • 3
    It's worth noting that this breaks the very useful pattern of a single return used in languages like c to create a single area to clean up resources before the return. The need for that is mitigated in other languages with exceptions which offer different techniques to ensure that resources are always closed: a finally block, using, try-with-resources... – candied_orange May 13 '17 at 14:48
-1

I would apply separations of concern.

Your example shows two responsibilities: checking the preconditions and doing actual work. I would put them in separate methods:

throwIfFileFailsChecks(file);
workWithFileContent(file);

The latter may be split up in even more methods having dedicated "concerns".

Timothy Truckle
  • 2,336
  • 9
  • 12
  • 1
    @CandiedOrange: Or, y'know, simply `if (fileNotFound) throw` which is arguably simpler than trying to trivially refactor. – Robert Harvey May 13 '17 at 15:08
  • *"cky! Abstractions are good but not when they require comments to understand."* Thats true. In Java I can declare the method to throw that exception which would make the comment obsolete. I don't know if PHP has a similar mechanism. Thats why I added the comment. – Timothy Truckle May 13 '17 at 15:09
  • 3
    If your name requires me to look at the declaration your name has already lost to @RobertHarvey 's traditional alternative. The names you put on abstractions should make the code easier to read. Not force me to scroll more. – candied_orange May 13 '17 at 15:11
  • @CandiedOrange *"If your name requires me to look at the declaration your name has already lost"* The names must express the responsibility of that method. They should not convey implications of their implementation. e.g.: what makes you think the *existence* of the file is the only reason to fail? – Timothy Truckle May 13 '17 at 15:15
  • 1
    Throwing is not an implementation detail here. It's part of the contract. I can't USE this properly without knowing it throws. You can't hide that it throws from me anymore than you can hide that a function returns something. – candied_orange May 13 '17 at 15:18
  • Anyway, you've already updated with the best name I can think of using if you insist on doing this rather then use @RovertHavey 's traditional if-throw code so I'm going to delete my outdated comments. – candied_orange May 13 '17 at 15:23
  • @CandiedOrange "you've already updated with the best name I can think of using if you insist on doing this"* Finding good names is the hardest part in programming. I usually need several tries... – Timothy Truckle May 13 '17 at 15:25
  • Ha, well I can't argue with that :) – candied_orange May 13 '17 at 15:26