I started developing a small project using node.js with express and socket.io. Node is a nice server and socket.io is great. However, I’m having issues with javascript. Currently, two things really get on my nerves:
1. the plus operator
Most of the hard-to-debug bugs in my javascript code come from the + operator. It decides to concatenate strings instead of add numbers. Considering that all stuff that goes over the wire (i.e. socket.io) is treated as strings, it’s really painful and ugly to have parseInt(…, 10) everywhere. PHP solves this issue with simple dot operator. Simple, no-brainer and always does what you expect. You don’t have to think where does the data come from.
2. foreach
I miss PHP’s foreach so bad. Consider:
for (ix in really.long[expression].toGet.theStuff) {
if (really.long[expression].toGet.theStuff[ix].value < 10 && really.long[expression].toGet.theStuff[ix] > 5) {
...do something
versus PHP’s:
foreach ($really.long[expression].toGet.theStuff as $ix=>$value) {
if ($value < 10 && $value > 5) {
....do something
Of course, one could assign the array element to some local variable, and so I have local variables all around wasting code lines and making code error prone (if you need to change the collection you are iterating, you have to change in two places).
For the game I’m making I have a bunch of array which represent a puzzle player needs to solve. Ensuring puzzle is solvable is CPU intensive, so I pre-calculated a couple of thousands of puzzles and select one randomly. Since puzzles are static data which is not going to change, I decided not to burden the database with this because DBMS is always overloaded with other stuff anyway.
My first thought was to build a big array and fetch a random element. I found some benchmark showing that this is faster than “if” or “switch”, however benchmarks excluded time needed to parse/create the array itself. Since every player is a new HTTP request, this huge array would have to be constructed each time. I am using APC, but I failed to find if arrays in precompiled PHP source file are stored “structured” as well.
Dropping the array idea, I though about “switch”, foolishly thinking that it would use some kind of jump-table and run the desired return statement. Something like this:
function get_puzzle($id)
{
switch ($id)
{
case 0: return array (...first puzzle...);
case 1: return array (...second puzzle...);
case 2: return array (...etc.
However, researching this I find out that switch performs similar to series of “if” statements… variable is compared with each “case”.
So I decided to roll my own solution using “if” statements, but not linear. I used a B-tree approach. Split by two until only one is left. This means it would take only 11 comparisons to reach a puzzle from a set of 2048. Here’s an example with set of 256 puzzles.
function get_puzzle_btree($id)
{
if ($id < 128)
if ($id < 64)
if ($id < 32)
if ($id < 16)
if ($id < 8)
if ($id < 4)
if ($id < 2)
if ($id < 1)
return array (...first puzzle...);
else
return array (...second puzzle...);
...etc.
Of course, I did not write this “if” behemoth by hand. A simple 20-line recursive function spits out the PHP code.
In the end, I wrote a simple comparison loop that tries to get all the puzzles and compares whether the old “switch” and new “btree” function return the same values.
I’m creating a gaming website and one of the games has a complex CPU-intensive AI. Many possible positions for player and computer need to be examined before heuristics can do their work. For this I stack the game state, play a hypothetical move and run AI on it again. The number of moves it looks ahead is configurable, but the more there are the number of possible combinations grows exponentially. This will run on the web server, so it has to consume as little CPU as possible.
The rest of the website is written in PHP, but I started considering something faster for this. Of course, when you want to go fast, you want C or C++. I know some Assembly as well, but it’s PITA to use. But, before “wasting” any time in using C and having to set up the compiler to build the executable for target server, I wanted to make sure there is a reason to do it.
The benchmark is very simple. An array and a big loop doing trivial stuff with it:
------------------- bench.c -------------------
int main(int argc, char** argv)
{
int i,j, arr[10] = {0,0,0,0,0,0,0,0,0,0};
for (i = 0; i < 100; i++)
for (j = 0; j < 1000000; j++)
if (arr[i%5+j%5] == 0)
arr[i%2+j%2] = 1;
return 0;
}
-----------------------------------------------
I compiled it with GCC 4.2.3. Here’s the PHP version:
------------------- bench.php -----------------
$niz = array(0,0,0,0,0,0,0,0,0,0);
for ($i = 0; $i < 100; $i++)
for ($j = 0; $j < 1000000; $j++)
if ($niz[$i%5+$j%5] == 0)
$niz[$i%3+$j%3] = 1;
-
I run it with PHP 5.2.5 cli
Now the results:
$ time -p php -f bench.php
real 97.32
$ time -p ./bench
real 2.11
Amazing! C seems to be 46 times faster. I must admit I really expected better results from PHP. I wonder if there is some way to improve PHP speed on this one.
My I guess was that PHP’s excellent duct-tape arrays come with a price. To check this, I removed the array access, leaving only the for loops inside:
$ time -p ./bench
real 0.33
$ time -p php -f bench.php
real 15.14
Looks like array access is not to blame. It is consistently 46 times faster.
Tests were done on Intel Core2Duo CPU clocked at 2.16GHz running 32bit Slackware 12.1. All the results are averages of 10 runs.
Update: it looks like there are other benchmarks, and they come to similar conclusion. Facebook reports PHP being 39 times slower.
I guess this will not be the first nor the last text comparing those two frameworks, but I got so amazed with Yii that I have to write it.
Let’s be clear, CodeIgniter is just a little bit more of a simple MVC framework. Yii is a complete web-development framework used for rapid web application development. Let’s compare them in detail…
CodeIgniter is great for beginners. If you barely have a clue what MVC stands for, I highly recommend it. It features great tutorials and is super-easy to learn. If you want to learn what MVC is and how to use it, take a look at CodeIgniter video tutorials. CodeIgniter enables you to go into coding really fast and create basic stuff quickly. But, that’s all. It’s great to learn MVC, and it works fine even for large websites. However, you have to do a lot of things by hand. If you’re experienced PHP developer you might even be used to that and you won’t see anything missing in CodeIgniter.
I built a couple of websites using CodeIgniter, most visited on is slagalica.tv with about 30k visits/day.
From 2009 on I was testing Yii, but I only got to use it for the real project last month. Be prepared, if you are not experienced with MVC frameworks, you might find the learning curve really steep. Yii is very powerful, but to harness the power you need to learn all the features and the way stuff is done in yii. Instead of just going in and coding, take some time to read the docs, wiki and create some simple small project to learn it. Whenever you are doing something that seems like too much manual work, look for ready-made yii-way solution.
So, what makes Yii so much better? I don’t know where to start, so I’ll just enumerate:
Example of site I’m building using Yii: setlopta.com. There’s a link to English version in top-right corner.
Using PHP’s serialize function to serialize and array or object where some element is a string with UTF8 data creates the serialized string properly. However, unserialize function fails to unpack that data. I ran into this when setting session flashdata from my CodeIgniter application. The solution I find to work (not sure if it’s perfect though) is to use mb_unserialize function (found in comments of PHP manual).
function mb_unserialize($serial_str) {
$out = preg_replace('!s:(\d+):"(.*?)";!se', "'s:'.strlen('$2').':\"$2\";'", $serial_str );
return @unserialize($out);
}
To use this with CodeIgniter’s session, just change Session’s _unserialize($data) function to use mb_unserialize instead of PHP’s original function. Grrr, I lost hours debugging this and finding a solution :(
Update: the problem became evident only because I used a wrong connection charset. Still I don’t like PHP returning an empty string when it cannot convert one character. I like the way some other programming languages are doing by placing a question mark (?) instead.
There’s a bug introduced between PHP 5.2.1 and 5.2.2 that affects
handling of Firebird blobs on 64bit machines. Having moved some of my
servers to 64bit Slackware (Slamd64 to be more precise) I run into
this problem.
Unless you want to recompile the whole PHP to a newer version with the
fix (5.3 as I understand, although did not test), you can patch the
sources: Just open ibase_blobs.c file and modify this function:
_php_ibase_quad_to_string
char *result = (char *) emalloc(BLOB_ID_LEN+1);
/* shortcut for most common case */
if (sizeof(ISC_QUAD) == sizeof(ISC_UINT64)) {
sprintf(result, "0x%0*" LL_MASK "x", 16, *(ISC_UINT64*)(void *) &qd);
} else {
ISC_UINT64 res = ((ISC_UINT64) qd.gds_quad_high;
sprintf(result, "0x%0*" LL_MASK "x", 16, res);
}
result[BLOB_ID_LEN] = '\0';
return result;
Rebuild the interbase.so, copy to extension directory, restart Apache and you’re done.
Today I started testing Yii framework. I have previous experience with
CodeIgniter so this will be a nice comparison.
I got a hold on to basic concepts, and first thing that made me stuck
for a while was doing the proper URL redirection to create SEO links
instead of index.php?r=controller/action. I set up .htaccess without
much trouble, but It turned out that default applicaiton generated by
Yii is missing this line in website/protected/config/main.php:
‘urlManager’=>array( ‘urlFormat’=>’path’, ‘showScriptName’=>false, ),
The line should be placed in ‘components’ section, at the same depth
as ‘log’ or ‘user’. All this using Yii 1.0, newer versions might have fixed it.
Stay tuned for more Yii experiences as I move along with the project.