Improve PHP Disk I/O & remove Race conditions by using '@' error suppression
blog.rodneyrehm.de
blog.rodneyrehm.de
Not this again! I've been working with PHP for over 10 years and seen @ suppression used at companies in the most ridiculous ways imaginable. The most common, and I believe incorrect, way @ suppression is used is when using fopen. Why do people do it so often? Probably because it says you can do so right in the php.net manual http://us2.php.net/manual/en/function.fopen.php and has so for years. I've really lost track of how many bugs I've come across over the years in production code that could be traced back to someone @ suppressing fopen warnings. I don't care if you read some blog where the author claims using @ suppression will give you a magical 1000% increase in performance. JUST DON'T DO IT.
Oh wow, that's impressively awful, way more evil than the other common "just turn off notices in php.ini" hack.
isset($array['key']) ? $array['key'] : null;
thinking I was simply ignoring those stupid "Undefined index" notices.Now I figure out I was also hiding "Undefined variable" notices when $array was not defined and a ton of potential errors when $array is an object implementing ArrayAccess.
Shame on me.
Thanks.
Note to self: grep the code at work for @. Purge.
Although there may be some scenarios where it's permissible, such as @unlinking temporary files when upload validation fails. It only happens in exceptional cases, the outcome is not immediately crucial, and you don't have any dependent operations.
All of this is moot when you do the following though:
- Set error_reporting to -1 (report ALL errors)
- Register a custom error handler that converts all errors to exceptions
This renders the @ operator useless (it'll throw an exception regardless). I personally prefer this since it enforces error handling discipline early on.
I guess a lot of the trouble with @ is that it affects everything that happens temporally-within the expression, but people often use it as if it only affects everything syntactically-within it... for instance, recently I came across something like:
// suppress warning for <2 results
@list ($foo, $bar) = returns_a_list(...);
... which would also hide any warnings that occur in the body of returns_a_list(), despite that being neither intended nor wanted.It's a shame the only @-free solutions to many popular uses of @ (like that one) are so hideously ugly. Also that I suspect that changing @ so it only affected syntactically-contained errors would be... impractical for the PHP team, for a number of reasons.
Yet another reason not to use smarty I guess.
added: Apparently someone on php.net agrees with you
http://php.net/manual/en/language.operators.errorcontrol.php...
they say it takes 1.7 times as long BUT that is only .005 ms in their example
The more deeply nested the callstack is when you supress, the bigger the performance hit (slight generalisation and slightly from memory).
Someone posted here a clear example of why (in earlier php5) it generates far worse opcode:
http://derickrethans.nl/five-reasons-why-the-shutop-operator...
EDIT: I am wrong. See below.
Wikipedia has what appears to be quite a comprehensive article about it:
http://en.wikipedia.org/wiki/Serbo-Croatian
Its scope is referred to as a "macrolanguage" here under ISO 639-3:
--EDIT
I hadn't even got as far as the disk i/o section, after reading no words can do justice to the complete lack of understanding shown here with regards to filesystems, caching, SSD's and linux.
Very much agree with you.
When I was first starting out programming commercially, one of the best bits of advice I received was something along the lines of "Take a step back and think about why you're using these crazy constructs - chances are there's a much simpler way of doing things."
The lesson being: if you're having to write code like this, chances are it's because you're creating a mess. Take a step back and work out a simpler solution.
Replace "PHP" with "Jewish" and would you find that comment of yours acceptable?
Edit: I can only assume that the down voters find discrimination acceptable behavior in this community.
Either way, I stand by my comments.
There are better ways to do PHP... and there is bad PHP code examples and also good PHP code examples like there is in any language.
As a contrived example, an article about "How I replaced my engine using a crowbar" might lead people to believe that is the ideal way to replace engines and have mechanics groaning everywhere. If however the article was "How I replaced my engine using a crowbar whilst stuck in the desert with no other tools to hand" then everyone would understand a) don't do this in normal circumstance, b) there is another way to do it in less normal circumstances.
OK I get that PHP doesn't support atomic operations, but there are so many different errors that could happen when working with files. Say a permissions error, if the permissions of the file were changed between it being created and deleted that's an issue that needs resolving before your tmp folder fills up, it's easy enough to fix and should be reported as an error (be it to the front-end or to a backend logging service).
Surely there is a better way to handle these race conditions without just ignoring all filesystem related errors.
The best/real solution is probably implementing flock so that it can issue real filesystem locks, rather than relying on a file resource.
We're using smarty at work now, and while we probably won't drop it in this project (too much working code written in it), we might learn something for the future.
Otherwise PHP itself is a template language. That is why you start it with <? tag.
Just keep short tags on [it's off by default on new installations but ON by default on all hosting sites] and you got a better template engine than smarty.
You do not want to type <?php echo htmlspecialchars($var, ENT_QUOTES) ?> every time you want to output data. (Yes, I know it could probably be written shorter but my PHP is rusty. My point still remains though, you have to remember to type it every time.)
You can then run this entire array through htmlentities or htmlspecialchars before doing include().
My guess is that whoever wrote the framework just heard about Smarty while in university, long time ago.
Smarty's parser/lexer is horribly slow. The 3.1.x branch has caused problems for us, such as corrupted compiles and broken nested blocks [1]. As evidenced by the article, the developers don't seem to know what they're doing. You should see the workaround for people with custom error handlers -- registering another error handler on top that checks the source of the error against registered template and cache directory paths!
[1] The bug was introduced in this particular commit (lines 237-241 of r4505): https://code.google.com/p/smarty-php/source/diff?spec=svn450... and later "fixed" here: https://code.google.com/p/smarty-php/source/diff?spec=svn456...
I believe Twig is a fast and secure PHP template language.
I'm used to Jinja2 in Python which is almost identical to Twig.
Has anyone used Twig who would share their experience?
Really, PHP itself is a fine templating language if used properly. Get to know the short tags (including the short echo <?=$stuff?>) and the alternative syntax for conditional statements and you are good to go.
I think most of the work here will happen in memory.
Surely file_exists() is simply an operation on the disk index where the relevant block will be sitting in RAM from the first point that the operation is done. Subsequent operations on the same data shouldn't involve hitting the disk again until an actual write has occurred. Provided you have sufficient RAM this sort of thing is what kernel page cache is designed for.
Not to mention that thinking about a frequently used performance critical piece of PHP code doing large amounts of @fopen() and @unlink() fills me with dread.
PHP warnings are a debugging tool, not a substitute for exceptions. Suppressing them is not the equivalent of a catching and ignoring an exception.
Putting locks everywhere in a futile attempt to prevent the filesystem from changing under you is futile. It's fundamentally an external i/o device out of your program's control. It is never safe or reasonable to infer from the result of one filesystem operation that a subsequent one will not fail.
process switching =/= parallel execution multi-threading =/= multi-tasking
Only certain single core processors can execute in parallel, so to say that it's possible to execute in parallel on a single core without specifying that not ALL single core CPUs can do it is bad form.