Drupal theme table "bug"
I happen to find another bug with Drupal theme table functions. Before reading further, make sure you know about theme table function. In cell information, you can pass use an array with header key to indicate that this cell is a header cell (TH tag). So the following code will generate a pair of TH & TD tags for you each rows.
$rows = array( array( array('data' => 'Col1','header' => true), array('data' => 'Col2'), ), array( array('data' => 'Col1','header' => true), array('data' => 'Col2'), ), ); $output = theme('table', array(), $rows);
The generated HTML will be something like this:
<table> <tbody> <tr class="odd"><th>Col1</th><td>Col2</td> </tr> <tr class="even"><th>Col1</th><td>Col2</td> </tr> </tbody> </table>
But take look at the below code:
$rows = array( array( array('data' => 'Col1','header' => true), array('data' => 'Col2','header' => false), ), array( array('data' => 'Col1','header' =>; true), array('data' => 'Col2','header' => false), ), ); $output = theme('table', array(), $rows);
It's logical if you use TRUE for header then Drupal generate a TH tag for you, and use FALSE as if not. But the surprise thing is the result is two THs instead of TH & TD.
<table> <tbody> <tr class="odd"><th>Col1</th><th>Col2</th> </tr> <tr class="even"><th>Col1</th><th>Col2</th> </tr> </tbody> </table>
Well, it's a not a serious bug. It just gives you undesired result. If you take a look at Drupal implementation you will see that Drupal use isset to check for header flag, but isset actually check for array key existence and as long as header field is exist, Drupal will always render a TH for you.
Is Drupal Tablesort broken in design?
Every Drupal developer knows about tablesort API. It's useful when you work with table list, especially is the tablesort_get_order and tablesort_get_sort functions. But I think these functions are broken in design. Here is how it is broken.
It's a good habit to separate the presentation and the business logic. In Drupal, we do this by introduce theme functions. Theme functions are only used to generate the presentation, or HTML code here and should not do any logic processing. When you work with a list, you will usually construct a query, fetch it to array and pass it to theme function to render the page. Sometime you have to travel the query result to do some custom business logic, to calculate a new value, for example. And I consider ordering the data is a part of business logic. But if you use tablesort API, you will likely to mix your business code with your presentation code, since table sort functions require you to have the $headers, which describes table headers, to get current sort field and sort order. Take it like you want to sort your data before passing it to theme function, but tablesort API requires some information which is not available in business function so everything is mixed up.
Through, there are some advantages for requiring $headers, such as you can hide your table schema from user. We can see a related issue is raised here, but I don't think any changes will be made. So we gonna keep $headers variable in our business code for a while.
Drupal Module Statistic
I have been a Drupal Developer for a while, and have been involved in some Drupal-related projects. What I really like Drupal is the large number of available modules in the community. But sometime, when I tried to look for a Drupal module, I often ran into an abandoned module or legacy module (no release for D6) or a module has no stable release at all. So I asked myself how many usable modules available in the community, and I have the answer today.
To answer the question, I write a small script that runs through Drupal.org project pages and collects module information. The information I collect includes public release information and tags. The script will put all of these information inside a sqlite file and later I will do the statistic on the result. The sqlite database is included in the attachment section, you can use it if you want.
Improve PHP file loading
I think you have already known that require/include is faster than require_once/include_one. But sometime, we also need the functionality of require_once but do not suffer from the performance tradeoff. So here is a better way to re-invent PHP implement.
function requireOnce($file) { static $dict=array(); if (!isset($dict[$file])) { require $file; $dict[$file] = true; } }
The idea is very simple: PHP array access is faster than require_once/include_one checking, so we just keep an array to store for loaded file. But the implement is not completed yet because we can have array key conflict here, requireOnce('path/to/file.php') and requireOnce('/absolute/path/to/file') will yeild an error. I shift the idea a bit to avoid the conflict: when we use require_once or include_once the file will always be a definition file, ie: a class or functions, and these files can be identify in other way by class name or a custom label. So I change the implement again
The best way to access PHP global variable
I have been playing with PHP minor optimization for a while, but this is the first time I go for it seriously. My question for today is what's the best way to work with PHP global variables and how to achieve best performance for it. Rumours say that global keyword is slow, so this is a good time to check it out. And I also want to check if the number of variables affects the performance of the method.
Setup
The first thing todo is to define how we can access a global variable. The below is the list of ways to access global method that I use for the performance testing.
1. Use global keyword
It can't be simpler.
global $value;
2. Access $GLOBALS array
Instead of using the global keyword. I will access the global array directly.
$GLOBALS['value'];
3. Access $GLOBALS array with reference
Like the above method, but using reference. This way may be faster because we don't have to access the global array again and again.
$value =& $GLOBAL['value'];
4. Access $GLOBALS array and assign the value later
In this method, I fetch the value first, doing stuff with this and assign it to the global scope again. The code below illustrate the idea of this method.
$value = $GLOBAL['value']; // doing stuff $GLOBAL['value'] = $value;
5. Using a global array
Instead of using global variables in global scope. I store all global variables in an array and access it later. This method is useful because it reduces variable conflictment when the application grows.
global $ARR; $ARR['value'];
6. Using a global object
Like the above method, but use an object to store the variable.
global $OBJ; $obj->value;
7. Static class variable
I use a class to manage static variable. Many modern developers use this way to store global variable and configuration.
class GLB { public static $vars; } GLB::$vars['value'];
8. Static function variable - reference return
This is a another way to store / retrive global variables. I want to compare it with other method to see how it's different to others.
function &globalzie($name) { static $vars = array(); return $vars[$name]; } $value =& globalzie('value');
9. Static function variable - reference parameter
The same approach, but different way to retrive the variable. I don't like the reference assign operator on the above method.
function globalize($name,&$var) { static $vars = array(); $var =& $vars[$name]; } globalzie('value',$value);