debuggable

 
Contact Us
 

Using if statements to express dependencies

Posted on 21/10/06 by Felix Geisendörfer

When I was hanging out with a friend of mine last night (a php programmer as well), we were discussing some of the coding both of us are doing right now. At some point I told him that in my current script (the FTP/SVN deployment thing), I started to use some if statements to express dependencies. At first he didn't know what I ment, and to be honest I can't remember using this technic in a project before either, even so I think I've known about it for a while. I went on explaining it to him and after a couple of minutes we both realized it's probably one of those little coding tricks you might learn after a decade of coding and something that is used way to seldom in peoples code. For that reason I think it's definetly worth a post on here, even so some people might already know about it.

But let me start with another little story. I had a very excellent math teacher ones, and one of my favourite quotes from him is "Mathematics is nothing but concentrated lazyness". Already being a coder when I first heard him say this, I always wondered what he would think about programming under this aspect ; ). Anyway, even so Mathematicians and Programmers are lazy folks, there is one species to top them both easily - the compiler (or interpreter in our case). Compilers are written with no other goal then making them as lazy (err optimized) as possible. Everything that doesn't need to be executed should not execute, saving cpu cycles where possible. Now usually you only notice this in the execution speed of your application, and it doesn't have a huge affect on the way we write our code. Ok we might have heard of certain assignment technics to be faster then others, and that it can't hurt to unset() uneeded variables sometimes. But here comes one thing that is very easy to understand, but almost never used.

Let's think for a moment now we would be the PHP interpreter. We would run the code, and sometimes we would hit expressions in if statements. Our only interest is to decide whether the expression will evaluate to true or to false. So, being very lazy err optimized we would stop evaluating the expression if it becomes clear that it can't become true anymore. Confused? Let me show a little example:

if (false && funcA())

In this if statement there is no way for (false && [x]) to become true. So why should we even bother evaluating [x] (funcA)? Well we shouldn't. And that's how the php interpreter acts. In the example above, funcA() will never be executed, because there is no logical point in doing so.

Now while this can lead to unexpected behavior and might turn into a nightmare of debugging, you can also use it to express dependencies. Because just like a human being, the php interpreter reads expressions from the left to the right. So if we have several chained expressions, and all of them are connected via a logic AND (&&), then the compiler will stop his evaluation process as soon as one of the expressions returns false.

A (bad) example would be that we have three functions called funcA, funcB and funcC. Each of them will return either true or false, and we only want to execute funcB if funcA has returned true and only execute funcC if funcB has returned true as well. So we could also say funcB depends on funcA and funcC depends on funcB. Using the technique from above we can avoid writing several nested if statements and put all of those functions in one simple expression:

header('Content-type: text/plain');

if (funcA() && funcB() && funcC())
    echo "Success\n";
else
    echo "Failure\n";
   
function funcA()
{
    echo "funcA\n";
    return true;
}

function funcB()
{
    echo "funcB\n";
    return true;
}

function funcC()
{
    echo "funcC\n";
    return true;
}

So in order for you to be able to play around with this, I added some echo's to each function so you can change funcA and funcB's return value to false and see that the dependend functions will not get executed anymore.

Now of course, this is not the Übersolution to all your coding problems, and it complicates some things like error handling. But just to show you a practical application from my current deployment script efforts, here comes a simple real world example:

if ($recursive==true && !$this->__ftpUploadDir($Ftp, $localPath.DS.$localFolder, $remoteFolder, $recursive, $bruteForce))
    $success = false;

This 2 lines of code contain quite some logic. The first question is if the $recursive parameter is set to true, if not skip the next command. But if the parameter is true, then make the recursive function call, and only if this call fails, switch our $success variable to false.

But I would not always recommend this technic. For example one part of my script looks like this:

if (!$this->__svnExport($Svn, $tmpFolder))
    return false;
   
if (!$this->__ftpConnect($Ftp))
    return false;

if (!$this->__ftpUploadDir($Ftp, $tmpFolder, $remotePath))
    return false;

Of course I could put all of those function calls into one single if statement. But would that really make my code more readable? I don't think so. There are cases when this technic will make your code more beautiful and easier to maintain, but there will also be many where you shouldn't bother to abuse the compilers lazyness ; ).

Oh and one thing I already mentioned was that this technic can complicate error handling. Because if you run several functions in a chain like this, and one fails, there is no easy way to figure out which one did. The best solution to this problem, is to use the powers of OOP. Because if all functions are executed on the same object, you can simply create an lastError variable for that object, and check it's value if the total expression evaluated to false.

Alright I hope this was useful to some folks out there, I certainly consider it to be a nice addition to my coding habits.

Little Update:
I just put this technic to another nice real world use, this time without an if statement:

$success = $DeployScript->beforeFilter($deployAction) && call_user_func_array(array(&$DeployScript, $deployAction), $params) && $DeployScript->afterFilter($deployAction);

if ($success==true)
    $DeployScript->log($deployClass.'::'.$deployAction.'() was successful.', 'success');
else
    $DeployScript->log('There was an error while executing '.$deployClass.'::'.$deployAction.'()!', 'failure');

-- Felix Geisendörfer aka the_undefined

 

You can skip to the end and add a comment.

Dieter@be  said on Oct 21, 2006:

I always had this habit of ordering "dependent" evaluations in the specific order, using the benefits of the && operator.
It's just so logical :-)

scott lewis said on Oct 21, 2006:

The idiomatic way of describing this behaviour is that PHP "short-circuits" boolean evaluation. Which is indeed more useful than languages that don't (such as Pascal). Although it does cause subtle bugs when bouncing between languages. :D

Bret Kuhns said on Oct 22, 2006:

My intro to OOP course went over this in the first couple weeks. I've been doing it for years, but this is great advice to those who didn't know you could do it :)

Felix Geisendörfer said on Oct 22, 2006:

Hmm seems like everybody knows this already, oh well maybe the ones who don't just didn't comment ; ).

Pacifists  said on Oct 23, 2006:

I was using that unconciously just cause it was a logical way to do things :) had no idea that it's even taught in OOP course :) and of course could have never ever been able to name it :)

klevo said on Oct 24, 2006:

This could save some lines of code but I really don't consider it best practice. You can't use it in C++ for example because certain compilers don't do such optimizations. It's not guaranteed that PHP interpreter will use such optimizations it the future.

This post is too old. We do not allow comments here anymore in order to fight spam. If you have real feedback or questions for the post, please contact us.