5

First off I know this question has gone around more than once here:

But the more that I fix all E_NOTICEs (as people say you should) the more I notice that:

  • I am micro-optimising
  • I am actually making more code and making my code harder to mantain and slower

Take an example:

Say your using the MongoDB PHP driver and you have a MongoDate object in a class var named ts within a class that represents a single row in a collection in your database. Now you acces this var like: $obj->ts->sec but PHP throws a fit (E_NOTICE) because ts in this case is not defined as an object in itself because this particular row does not have a ts field. So you think this is OK, this is desired behaviour, if it's not set return null and I will take care of it myself outside of the interpreters own robotic workings (since you wrap this in a date() function that just returns 1970 if the var is null or a none-object).

But now to fix that E_NOTICE as another developer really wants me to since having ANY E_NOTICEs is terribad and it makes the code slower to not do it according to the errors. So I make a new function in the $obj class called getTs and I give it 3 lines, literally to do nothing but check if the ts var is a MongoDate object and return it if it is...

WHY? Can't PHP do this perfectly fine for me within its much faster interpreter than having to do it within the runtime of the app itself? I mean every where I am having to add useless bumpth to my code, pretty much empty functions to detect variables that I actually just handle with PHPs own ability to return null or checking their instanceof when I really need to (when it is vital to the operation and behaviour of the said function) and don't get me started on the isset()s I have added about 300 lines of isset()s, it's getting out of hand. I have of course got to make this getTs functions because you can't do:

class obj{
    public $ts = new MongoDate();
}

I would either have to store the ts within the __constructor (which I am not too happy about either, I am using a lot of magics as it is) or use a function to detect if it's set (which I do now).

I mean I understand why I should fix:

  • Undefined vars
  • Assigning properties of unset vars (null vars)
  • constant errors etc

But if you have tested your code and you know it is safe and will only work the way you desire what is the point in fixing all of the undefined index or none-object errors? Isn't adding a bunch of isset()s and 2 lines functions to your code actually micro-optimisation?

I have noticed after making half my site E_NOTICE compliant that actually it uses more CPU, memory and time now...so really what's the point of dealing with every E_NOTICE error and not just the ones that ARE errors?

Thanks for your thoughts,

Community
  • 1
  • 1
Sammaye
  • 43,242
  • 7
  • 104
  • 146

2 Answers2

6

You do certainly do get better performance by using isset(). I did some benchmarks, not too long ago, and just hiding errors came out to be about 10x slower.

http://garrettbluma.com/2011/11/14/php-isset-performance/

That said, performance usually isn't a critical factor in PHP. What does, personally drive me crazy is silent errors.

When the interpreter chooses to not flag something as an error (which could lead to instability) is a huge problem. PHP in particular has a tendency to

  • warn about things that should error (e.g. failure to connect to database) and
  • issue notices about things that ought to warn (e.g. attempting to access a member of a null object).

Perhaps I'm just overly opinionated about this kind of stuff but I've been bitten before by these silent errors. I recommend always including E_NOTICE in error reporting.

Garrett Bluma
  • 1,312
  • 10
  • 14
  • 1
    +1 Nice link, I am thinking of benchmarking my site in a min, I am serious when I say that dealing with all the E_NOTICEs is slower than letting PHP just access the error object. In fact the new code just downed my server because it actually filled the entire memory with objects...All I did was add one function to define a new object if it doesn't exist....the only difference :\ – Sammaye Jul 16 '12 at 19:27
  • 1
    It may not be an option, but look into Xdebug. You can profile your code and figure out where the time/memory is getting spent the fastest. (WinCacheGrind is a good profile viewer too.) – Garrett Bluma Jul 16 '12 at 19:30
  • Aye I will have to profile a little, in theory my code should be using one spot of memory each iteration but it's not, prolly a coding error but still that's just one example where things are slow there are much harder to explain places... – Sammaye Jul 16 '12 at 19:40
3

Whether or not you should fix them is certainly debatable, and will just depend on the return in your situation; eg, it's more important if the code will have a longer life-span, more devs, etc.

In general, assuming that your functions will be used (and mis-used) by someone else is the best practice, so you should do isset/!empty/is_object checks to account for this. Often, your code will find it's way into uses and situations you never intended it for.

As far as performance, Every time any kind of error is thrown--E_NOTICE included--the interpreter spins up the error handler, builds a stack trace, and formats the error. The point is that, whether or not you have them reporting, errors always slow execution; therefore, 2-3 function calls to avoid an E_NOTICE will still improve your performance.

Edit: Alternatives for the above example

I wouldn't necessarily create extra objects to avoid the errors; you can gracefully avoid them without. Here are a couple of options:

1) Function that handles missing ts:

SpecialClass class {

    funciton getTs () {
        return !empty($this->ts) ? $ts->sec : false;
    }
}

2) Deal with missing ts in template/procedure:

if (!empty($obj->ts->sec)) {
    //do something
}

I particularly like empty() because you can use it to replace of (isset($var) && ($var or 0 != $var //etc)), saving multiple calls/comparisons and empty never throws notices for the target var or attribute. It will throw an error if you're calling it on a proptery/member of a non-existent variable.

Bryan Agee
  • 4,924
  • 3
  • 26
  • 42
  • So say I have a activity stream with 20 items on. In my example above each would have a ts of a `MongoDate` object. It is quicker and more efficient to create a new object in each parent object `$obj` and do a calculation on that variable than it is to allow PHP to call the global error function, builtin or predefined by the user? – Sammaye Jul 16 '12 at 20:16
  • Either that (although I would recommend returning false if it's not set, rather than creating one extemporaneously) or simply testing the return before you use it: ie : if (!empty($obj->ts)) { //do stuff; } or $ts = !empty($obj->ts) ? $ts->sec : //fallback value; – Bryan Agee Jul 16 '12 at 20:25
  • Meh decided to just knuckle down and do it in the end. I have still noticed increased CPU and memory comsumption even though all I have done is added more IF statements for decision making based on whether the object exists or not. Might do a whitepaper on it actually. This method is so ugly in HTML and PHP is supposed to be a dynamic language...but anyway thanks. – Sammaye Jul 18 '12 at 07:51