Blog

Bad uses of the @ operator

In PHP, @ is called the error suppression operator. It is sometime a convenient way to tell PHP that it shouldn’t generate a warning (or a notice) at some piece of code because you know it’s perfectly correct to ignore that particular warning. I’ve found out that the @ operator, if overused, can impose an important speed penalty. Hense, here is a list of things you shouldn’t do with this operator.

Replacing isset

When you have a variable that you aren’t sure is set, do not use the error suppression operator to remove the “variable not set” notice, it’s about 2 times slower than using isset. Example:

if (isset($albus))  $albert = $albus;
else                $albert = NULL;

is equivalent to:

$albert = @$albus;

but while this second form is a nice syntax, it runs about two times slower. A better solution is to assign the variable by reference, which will not trigger any notice, like this:

$albert =& $albus;

However, using this assign-by-repherence trick may induce unintended side effects if you were going to modify any of the two variable later. My rule is to use this trick only in performance-critical areas and where I’m sure it won’t affect anything.

With the list construct

PHP allow you to assign multiple variables at once from an array using the list construct. The most common case of list is with the explode function which simply split a string in multiple parts. For example:

list($a, $b, $c) = explode('/', 'part1/part2/part3');

But often, you cannot be sure that the string you’re “exploding” has as many parts as you have variables listed. This will result in a PHP notice which is easily dismissed with the error suppression operator:

@list($a, $b, $c) = explode('/', 'part1/part2');

and in this case, the variable $c will be set to NULL. But again, @ is pretty slow. It’s so slow that, for this example at least, I’ve found that it’s faster to use array_pad to fill the array so that it contains enough values like this than to use the error suppression operator:

list($a, $b, $c) = array_pad(explode('/', 'part1/part2'), 4, NULL);

That’s getting pretty ridiculous.

The best solution I have found is to assign each variable by reference, like this:

$result = explode('/', 'part1/part2');
$a =& $result[0];
$b =& $result[1];
$c =& $result[2];

Since you weren’t going use $result anyway — you were using list which did not assign the full array to any variable — assignment by reference shouldn’t cause much trouble. From my testing, this is a little slower than using list, but still way faster than anything using the error suppression operator.

Conclusion

So what is to be remembered from all this? Simply don’t use the error suppression operator with speed-critical code. Writing more code to work around the tricky cases will always be faster.

Of course, if you don’t care about notices (most probably because you have set the error level to not include them) you don’t need any of these tips because you don’t need the error suppression operator for variable assignment. But if you’re deploying your software around on servers which do log notices, hopefully this information will be handy. At the very least, it will be for me and my PHP projects.


Notes: All tests were done with PHP 5 with error reporting at E_ALL. Results may vary with other versions and other settings.


Merry Christmas

I realize I haven’t posted much this December, or so it seems from the English side of my website. I’ve been busy with some projects, including Reflex, a website contract, and a series of article in French about the ongoing electoral campaign here in Canada where I ask candidates in my district what they have to say on different subject. If you can understand French and want to read them, see “Question d’élection”.

I also take this occasion to wish my readers happy holidays! And I want to say I won’t stop posting for these holidays, whatever that means. :-)


Bug-Fix Day

Today is my bug fix day. I’ve corrected small problems in Gamma Control and PHP SmartyPants that would have been detected if I had tested things better. There is also a fix for a problem PHP Markdown and PHP Markdown Extra which appeared on november 28, release date of PHP 5.1.1.

Gamma Control 3.0.1

  • Corrected a bug where it failed to update the gamma settings after a text field was edited, and where some text fields would not accept values in the correct range.

  • Native support for Mac OS X when running on Intel processors.

PHP SmartyPants 1.5.1e

  • Fix for a bug that prevented special characters from being escaped.

PHP Markdown 1.0.1c & PHP Markdown Extra 1.0.1

  • Fixed a problem occurring with PHP 5.1.1 due to a small change to strings variable replacement behaviour in this version.

Reflex — Templates, Part 2

In my previous entry about Reflex templates, I talked about how database queries are built to fit the template needs. From a web application framework developer standpoint, this means less code is needed to control page display. It also gives more flexibility to the template designer who is no longer limited by what the application developer makes available to him. But this template-does-the-query principle can be pushed even further. Now let’s build a form!

Creating a form is dead easy in HTML. Creating a form that works however require some programming skills on the server side. Well, not so with Reflex templates. Write your form just as you’d write an static template and it’ll work:

<rx:form>

<p>
<label>
  Entry Title:
  <rx:input type="text" source="entry/title"/>
</label><br />

<label>
  Entry Content:
  <rx:textarea cols="80" rows="20" source="entry/content"/>
</label>
</p>

<p>
  <rx:input type="submit" perform="update"/>
  <rx:input type="submit" perform="delete"/>
</p>

</rx:form>

Notice the <rx:input> and <rx:textarea> tags. They take the same attributes as HTML’s <input> and <textarea> tags, and will sent rendered as such to the browser with small transformations. Each of them will automatically get a name attribute. First <input>’s value attribute and <textarea>’s content will be filled with the data found where the source attribute points to.

The <rx:form> element will be changed to a standard <form> with an added action attribute current location and a method="post" attribute. The two last <rx:input> have a type="submit" attribute and will be rendered as buttons by the browser. Because they have no display name, Reflex fills the value attribute of the two submit buttons.

Finally, when you submit the form, Reflex takes all the inputs and calls the action associated with the perform attribute of the clicked button. And you’ve updated, or deleted, your entry.

But wait a minute, isn’t that totally insecure? What if I don’t want people to delete my entries? The obvious answer would be “remove the delete button” which, of course, does nothing to prevent a malicious user from sending faked input that will perform the action anyway. Or is it? If you remove the delete button, Reflex will no longer accept to perform a delete action from this form. This is totally WYSITFIAYCDWTFWhat You See In The Form Is All You Can Do With The Form.

There is more.

What if you want to edit all your entries at the same time… how’d you do that? Well, it’s as simple as if you wanted to display all your entries on the same page; wrap your inputs in a list:

<rx:form>

<ul>
  <rx:list source="weblog/entry" as="entry">
    <li><rx:input type="text" source="entry/title"/></li>
  </rx:list>
</ul>

<p><rx:input type="submit" perform="update"/></p>

</rx:form>

Isn’t it nice? Note that instead of <rx:list> with some attributes, I could have used the shortcut <rx:entry-list> as I did in part 1.

So you can make pretty much any kind of form with this template system. The best part is that they are handled automatically for you. It’s powerful enough to make the entire Reflex administration interface work with this.

You may have noticed that all these examples are about weblog entries. That does not reflect any limitation: Reflex will be capable of handling all kind of data this way. How the data is stored and how different actions are performed is defined by modules. That will be the subject of my next Reflex entry.



  • © 2003–2025 Michel Fortin.