PHP notice suppression; only certain circumstances

2019-05-07 17:40发布

问题:

tl;dr - Is there an effective way to manage the error reporting level of PHP when working in a very strict environment, given certain processes would be made easier with a less strict level?

Alright; first off, I don't believe "error suppression" is a solution. I (am reasonably certain that I) have never used the @ error suppression operator, and have no intention of doing so. I take advantage of set_error_handler() and ErrorException (or some derivation of) and I develop in an error_reporting(-1) (future proof E_ALL | E_STRICT)

Now, I don't want to change these habits, as I find they are a great practice (also; if anyone has suggestions to further improve my development/production environment settings/practices, I'm all ears)

However, when it comes to view generation this can get slightly tedious. The correct data (array indices, variables, etc.) are not always available, given a controller fails to pass certain data to the view for whatever reason. As long as this data is non-critical to view generation, the view should still render.

I rather like this syntax as it's not verbose but (I think) highly understandable:

// e() is a shortcut function; given the passed value evaluates to a boolean true
// it will echo() and return true, otherwise it simply returns false
<p><?php e($data['field']) or e('No data found'); ?></p>

Of course, if $data['field'] isn't invoking offsetGet() with null returned in absence of the index, we have a problem. Notice meet exception, exception meet script failure.

I've experimented with different implementations, including creating a data tree using a node-like class to manage lists/rows of data passed to the view. __get() would actually create nodes (on assignment or access) that don't exist (as to simplify node data assignment, and to prevent issuing notices. __isset() tested for validity and would return false appropriately though) It also implemented ArrayAccess for accessing the node data, and would simply return null on a missing index.

I've opted to abandon this implementation due to the overhead of PHP's magic (though I learned alot about refactoring/optimization and profiling)

I've gone with native arrays instead, but now the codebase for my views is littered with isset(), and frankly that's just irritating (nearly more than the performance loss of the aforementioned implementation)

Now, I was thinking the easiest fix would be to slide the error_reporting() notch up and down based on where we are in the script:

// View::render()
public function render($data){
    error_reporting(E_ALL & ~E_NOTICE);
    // view generation logic
    error_reporting(-1);
}

But that doesn't seem like the cleanest (nor safest) fix; especially when helper functions are called within a view. I've gone for a sort of HMVC approach, and sub-requests can be issued from a view, so I'd need to find all the render() escape points and guard them with error_reporting(-1).

Do I have any other options?

回答1:

"undefined variable" notices are very valuable, even in view templates, as they help to spot typos; but this requires to either define every variable in the controllers, or to check if they are set in views.

As you noticed, the two obvious solutions have some overhead or drawbacks. Even disabling error reporting has some overhead since errors are still generated (the error message is formatted, internal and user error handlers are called, etc; they are just hidden). And this hides errors from helper methods you may call from the views; this doesn't helps debugging.

I would recommand you to go with a template engine. Some generate PHP code as fast as hand-written code. They will handle this for you, and will do more (like escaping, your views should also be littered with htmlspecialchars() calls ;) ).



回答2:

Keep reporting E_NOTICE, it's worth it. That said, I agree that Undefined Index is not the same caliber of error as an undefined variable, and isset($options['boolean_flag']) && $options['boolean_flag'] is a bit ugly. A project I work on has thousands of those notices, so in order to keep seeing E_NOTICE-level errors without getting flooded by Undefined Index, I actually recompiled the language to ignore that particular type of notice. (I'm using HHVM rather than PHP, but it's the same difference).

Yeah, that's an extreme solution, but it is an option in a tight spot. Obviously you'll want to use an official build on production.

Note: I wrote down the steps to recompile and could post that if anyone would like to try, but it's a little outside the scope of the original question.