Node.js vs. PHP

by Azat Mardan on September 3, 2013

The modern web is always changing, and this article is more than two years old.

By Azat Mardanov

PHP is not going to disappear soon, but its position is being undermined even further by the nascent Node.js. When the Internet exploded in the 2000’s, PHP was the thing “all the cool kids” did. PHP caught on because:

  • It was an interpreted language, unlike C++ or Java which require the source code compilation;
  • It had the ability to be used directly within HTML in its template files;
  • It had cheap, shared hosting providers on Apache servers with a Linux, Apache, MySQL and PHP (LAMP) stack;
  • It had a functional nature, which is easier to learn than the object-oriented programming.

Over the years, PHP and its apps became vulnerable to security threats (e.g., SQL injections), lacked a centralized packaging registry (was Composer inspired by Node Package Manager?), had an inconsistent API and suffered from subpar performance. It’s easy to argue that there are better alternatives to PHP, for example Ruby on Rails and Django, however nothing is as approachable as Node.js.

For those of you who aren’t familiar with Node.js, or who have heard of it but can’t quite grasp the concept, I like to say that it is functionally similar to the PHP + Apache or ASP + IIS stacks. Nowadays, it is also gaining momentum.

The platform uses JavaScript and its non-blocking I/O mechanism allows for a excellent performance. Node.js also comes with a robust package manager solution npm (which stands for Node Package Manager). However, because Node.js is a lower-level technology, it is not comparable to complex frameworks like Struts, Rails or Django directly.

Many people, whether software engineers or entrepreneurs, are often faced with the decision: “What tech stack should I use?” In this article, I’ll try to compare PHP and Node.js using an apples-to-apples approach, looking at the question from different angles including:

  • Syntax
  • Context switch
  • Modules
  • Ecosystem
  • Frameworks
  • Real-time apps
  • Database apps
  • Third-party services apps
  • Web servers
  • Hosting
  • Performance

Disclaimer

As this article reflects my own opinion, I wanted to start by clarifying my background as it might be reflected within my point of view.

I’ve worked with many technologies including Ruby on Rails, Python, Java/J2EE, VB, ASP, Perl and, of course, PHP. One of my most complex PHP projects was openList.co which involved the use of the MVC pattern with template engines, classes, a database abstraction layer and .htaccess re-routing.

However, during the past couple of years, my focus has been dedicated solely to Node.js and front-end JavaScript frameworks like Backbone.js. So my opinion might be biased. Please feel free to comment based upon your own experience with real projects in both PHP and Node.js. If you want to learn more about Node.js take a look at my book Rapid Prototyping with JS or the coding intensive full-time course at HackReactor.

Syntax

This section looks at some simple code examples so that you can compare the syntax of PHP and JavaScript (which, as we mentioned, is what Node.js is based upon). Both platforms can be accessed to the command line interface via $ php -i and $ node.

For example, this snippet prints “Hello World” in PHP:

echo 'Hello World';

This will output the same in Node.js:

console.log('Hello World');

Note: In JavaScript semi-colons are optional except when inside of the for loops and before immediately-invoked function expressions (IIFE).

The following is the sleep function in PHP:

echo "a"."n";
sleep(2);
echo "b"."n";
echo "c"."n";

The above code will output:

a

…and then after a 2 second delay:

b  c

If we try to re-write this code in Node.js:

console.log('a')
setTimeout(function() {
  console.log('b')
 },2000)
console.log('c')

…this snippet will print:

a  c

…and, after a 2 second delay, it will print:

b

Why the difference in output? The setTimeout() function is asynchronous, meaning that the remaining code does not stop executing while that function is processed.

Note: In JavaScript, console.log() automatically adds the end of line symbol.

The for loop in PHP might look like this:

for ($i = 1; $i <= 10; $i++) { 
  echo $i;
} 

It’s strikingly similar in Node.js:

for (var i = 0; i <= 10; i++) { 
  console.log(i);
}

Create an array in PHP:

$users = array( 
  array('name' => 'John', 'id' => 3940), 
  array('name' => 'Peter', 'id' => 8904) 
); 

To create an array in Node.js:

var users = [ 
  { name: 'John', id: 3940 }, 
  { name: 'Peter', id: 8904 } 
]

To iterate through an array in PHP:

for($i = 0; $i < count($users); ++$i) { 
  $users[$i]['id'] = mt_rand(000000, 999999); 
}

To iterate through an array in Node.js:

for (var i; i < arr.length; i++) {
    users[i] = Math.floor(Math.random()*1000000);
}

Or in a functional manner:

users.forEach(function(user, i){ 
  users[i] = Math.floor(Math.random()*1000000); 
})

To declare a function in PHP:

function hello($name) {
  echo "Hi ".$name;
}
hello("Peter"); //outputs Hi Peter

To declare a function in Node.js:

function hello(name) {
  console.log('Hi' + name);
}
hello('Peter'); //outputs Hi Peter

To declare a new object in PHP:

class foo {
    function do_foo()  {
        echo "Doing foo."; 
    }
}

$bar = new foo;
$bar->do_foo();

To declare a new object in Node.js:

var foo = function () {
  return { 
    do_foo: function () {console.log('Doing foo');}
  };
};

var bar = foo();
bar.do_foo();

Note: there are no classes in Node.js/JavaScript, because objects inherit directly from other objects (prototypal inheritance). There are many instantiating patterns such as pseudo-classical, functional (as above) and classical.

A database snippet with the PDO database connection library in PHP:

$pdo = new PDO('sqlite:users.db');
$stmt = $pdo->prepare('SELECT name FROM users WHERE id = :id');
$stmt->bindParam(':id', $_GET['id'], PDO::PARAM_INT); //execute();

A Node.js database script with the Mongoskin MongoDB library:

//assuming we use Connect/Express middleware for req.query
var db = require('mongoskin').db('localhost:27017/db'); 
db.collection('users').find({_id: req.query.id}).toArray(function(err, results) {
    if (err) throw err;
    console.log(results);
});

Context Switch

The switch between different environments and languages is attributed to a drop of efficiency when writing software code. Research and personal anecdotal observations show that interruption negatively impacts programmers’ performance. With less languages to learn and remember, the flow is smoother and the code is better. For a deeper articles on this subject you might want to take a look at Human Task Switches Considered Harmful and The Multi-Tasking Myth.

PHP

With the LAMP stack (i.e, Linux, Apache, MySQL and PHP), developers must master at least two more languages which are PHP and SQL in addition to the mandatory and omnipresent HTML, CSS and JavaScript.

Node.js

Node.js is brilliant at having less context switches, because together with MongoDB, this stack can operate only in one language: JavaScript.

Here’s an example of MongoDB shell commands (called by $ mongo):

> db.users.find({});
> db.users.insert({name: 'Azat', email: [email protected]'})
> db.users.update({name:'Azat'},{$set:{email:[email protected]'}})

Modules

PHP

There is PEAR, a veteran system which installs packages on a server globally, and a better alternative, Composer.

In other cases, developers have to seek out modules – or components as they call them – on various websites, and to administer them manually by placing *.php files into sub-folders of their projects. Unfortunately, all this is not very kosher.

Node.js

Node.js comes with a superior and dependable package management system called npm and its registry (npmjs.org) which is easy to use and publish. Everything is administered via the package.json file and versioned locally, unless we’re installing a CLI tool with the -g option.

Ecosystem

PHP

This is probably one of the most important areas where PHP still beats Node.js. There are amazing open-source applications like WordPress, tons of free scripts, quality tools and books.

Node.js

Node.js is growing faster than any other platform/language. This is mostly due to the philosophy of keeping modules minimal and performing only a small set of tasks. Other factors might include such things as:

  • The popularity of front-end JavaScript among web developers
  • Existence of specs and an abundance of JavaScript resources and gurus amassed during the language’s many years of existence
  • A collaborative open-source community, mostly on GitHub
  • Ease of npm use (to publish an NPM module run $ npm publish).

As a result, some people predict that Node.js will surpass other languages in the absolute number of contributions.

Frameworks

It’s important to have rich tools and proven libraries at our disposal.

PHP

CakePHP and Zend come to mind first, but for more choices there is an extensive list.

Node.js

Playing field is relatively level, with Express.js being the most popular choice and full-stack MVC frameworks like Meteor and Derby growing quickly.

Real-time apps

PHP

For PHP, there is the Node.js-dependent Elephant.io and some other approaches. The problem with native PHP and websockets is that Apache and IIS — where PHP is usually run as a module — weren’t really built with a persistent connection in mind. Therefore, developers have to use the standalone processes like Apache WebSocket or Ratchet.

Node.js

Building real-time apps is just a breeze with the Node.js stack using Socket.IO library with the Express.js framework and the Handlebars reactive template engine. In the Meteor and Derby projects, building real-time apps is taken one step further by combining front and back end code bases with a persistence layer, which reduces the complexity and speeds up the development dramatically.

Database apps

PHP

PHP has a long and fruitful history with traditional, relational databases like MySQL, hence the name of the stack LAMP — Linux, Apache, MySQL and PHP.

Node.js

Node.js is natural with NoSQL databases like MongoDB.

The database performance is somewhat comparable to MySQL depending on the use case (for reference, see MySql vs MongoDB performance benchmark (MySQL), Simple Test : MongoDB vs MySQL (MongoDB) and MongoDb vs MySql – Fight!!! (MongoDB) articles). However, MongoDB is superior for distributed databases and is highly scalable. The added bonus is that without a fixed schema, NoSQL databases are perfect for cloud computing, prototyping and agile projects.

Third-party services apps

PHP

As is the case with many traditional languages, PHP’s flow is blocked until the remote server has responded, hence the need for multi-threading.

Note: Some languages provide this feature when special libraries/frameworks such as EventMachine for Ruby or Twisted for Python are used. However, they’re very complex and weren’t built from the ground up with the platform.

Node.js

On the contrary, due to its non-blocking I/O, Node.js can handle multiple requests and make multiple requests as a client to third-party services (e.g., Twitter, Amazon) with just one thread of execution.

Web Servers

PHP

Since PHP 5.4 and higher, there is a built-in development server that we can be started with:

$ php -S localhost:8000

Assuming we have an index.php in that folder:

<?php echo 'Hello World';  ?>

For versions prior to 5.4, there are “all-in-one” tools like MAMP and XAMPP.

As for the production environment, PHP can’t be run on its own. One of the most popular technologies used with PHP is Apache and nginx, where PHP is just a module of Apache web server. My personal experience with Apache is that it has a steep learning curve and while being very configurable, by default those configurations are prone to security leaks.

Node.js

Node.js was created from the ground up for the network applications and there is a set of core modules to write web servers.

We can start a Node.js server with:

$ node .

…assuming our index.js file in this folder has the code to create a new server such as:

var http = require('http');
http.createServer(function (req, res) {
  res.writeHead(200, {'Content-Type': 'text/plain'});
  res.end('Hello Worldn');
}).listen(1337, '127.0.0.1');
console.log('Server running at http://127.0.0.1:1337/');

In production, Node.js can be run on SmartOS or Linux (like Ubuntu) as a service.

Note: Multi-threading is absolutely possible in Node.js with clusters and/or external modules.

Hosting

PHP

PHP owes its popularity in large part to the ease and cheapness of shared hosting solutions. True, it’s hard to find one without the LAMP stack on it. This commoditization sometimes leads to security holes and less than acceptable downtime due to hosting providers overselling and other consumers using malicious code.

Platform as a Service is a better alternative, being somewhere in between a full-fledged, dedicated server and shared hosting. Most of PaaS providers support PHP right of the gate.

Node.js

Node.js works nicely on PaaS’s, with Heroku and Nodjitsu leading the list. Also, the cloud infrastructure company Joyent (the maintainer of Node.js), developed a powerful operation system SmartOS that allows for performance bursts, painless deployment and DTrace debugging.

Performance

It’s needless to say that performance is important. This resource shows different benchmark tests: Which programs are fastest?.

PHP

PHP is relatively fast but due to its bottleneck in the file system, database and third-party requests, it fails miserably in comparison with Node.js and its super fast V8 engine.

For example, when Facebook reached its scalability limits with PHP, they wrote an extremely fast C++ library and virtual machine which they called HipHop VM, but kept the PHP API.

Node.js

Node.js is extremely fast due to its non-blocking I/O mechanism and V8 engine technology. I have even heard that Joyent started re-writing some of their C++ modules in Node.js.

Conclusion

PHP was an outstanding technology in its day. Its success and popularity came from:

  • Its ease of learning and use;
  • Availability of cheap and straightforward hosting mostly using shared LAMP servers;
  • Abundance of open-source scripts, apps and libraries.

At the same time, it is my opinion that these same things now lead to its dusk. The contributions to the core from beginner programmers modified the API inconsistently while the lack of OOP/classes and module management systems inhibited open-source community growth. Absence of a leading framework (Ruby on Rails comes to mind as an example of a single dominant framework for a language) or programming paradigm also helped to produce a lot of bad code that relied heavily on mixing PHP and HTML code without any separation of concerns. On the other hand, there are a lot of good products and infrastructure built on PHP that are here to stay for the time being.

Node.js is relatively young, with only three years since its first commit, but it’s already the fastest growing platform by the pace of contributions (and the absolute number will surpass other languages in a few years). The fact that the JavaScript language is the most popular language in the world and has the biggest attributed to that. Many tools are ported to Node.js with little or no modification from the browser environment. Also, great books on JavaScript fundamentals (for example, JavaScript: The Good Parts and Eloquent JavaScript) have experienced a surge in the popularity again. Most importantly perhaps, Node.js is very efficient and great for building real-time, NoSQL-oriented, scalable systems.

This article was originally published at http://webapplog.com/php-vs-node-js/