Do not miss other articles on this subject:
Now it's time to compare the Javascript language to the PHP language. By the way, I will not talk about various browser's implementation:
we will compare apple with apple here, so we will talk about Javascript inside of Node.js.
The PHP language
PHP is probably the most hated language. There are tons of PHP bashing articles in the world. But what exactly is PHP and why the hate?
It's hard to tell exactly what PHP is.
PHP looks more or less like a random and extensive compilation of tools.
This is probably what make it simultanously great and bad:
everything exists in the core language: procedural, class-based OOP with lot of features, tons of functions and methods...
You want to manipulate arrays?
There is probably a builtin function doing what you want already
: you don't have to code it by yourself.
So you can focus on your application business logic.
You like OOP?
PHP features
almost everything that a class-based programming language has
: classes, abstract classes, final classes, inheritance, constructors, destructors, static methods, interfaces, scope resolution, late static binding...
except a strong type hinting...
And that's what make people angry about PHP.
There is always a
"but"
or
"except"
at the end of the phrase.
All design pattern can be implemented easily in PHP, since its OOP has been inspired by C++ and Java.
You can even do more.
Because PHP behaves like a dynamic language too, you have
magic methods
that allow you to perform some cool but unpopular things. For example there are magic getters and magic setters that are called everytime you try to access a property that does not exist. Since PHP doesn't mix method's and member's namespace in an object, they cannot clash. There is also a magic method called everytime you try to access a method that does not exist.
There are some interesting use cases for this: e.g.
one can build a simple xml lib where your object map exactly the XML tree... and there
IS
in fact a lib called SimpleXML that takes advantage of this. Back in my PHP's day I coded a lib inspired by SimpleXML but without its various gotcha.
It was fun and entertaining, and I found the language really flexible.
Combo that with the
ArrayAccess
interface, and the lib was allowing one to navigate easily from an XML node to another,
in a concise manner, in a way that cannot be done in C++ or Java.
There is also the
traits feature
that is useful once in a while. It permits class aggregation. It's useful because PHP does not support multiple inheritance. It's not a bad thing, since multiple inheritance is broken by design...
see the diamond problem
.
So it's untrue to claim that PHP's OOP is badly designed.
PHP is great at copying and integrating every language features that its creators want.
It even integrates
goto
, a feature that was introduced a very long time
after
the OOP's introduction: that one caused probably the greatest shitstorm in the entire PHP life! In fact,
PHP can shamelessly absorb anything.
So that's turn out to be the main problem with PHP: its lack of identity. It was a procedural language, then becames an OOP language, so
more than often, PHP is totally schizophrenic about that. Some core features are sometime functions, thus polluting massively the global namespace, sometime they are behind a class, and sometime they use
BOTH!
Yay, you read it: PHP core itself does not know who he/she/it is. Example? The
date_*
function collection and the
DateTime
class,
you can use both
DateTime::diff()
and
date_diff()
.
Okey, this is not critical, but
that's what make PHP the Frankenstein of programming languages.
From Wikipedia:
One criticism of PHP is that it was not originally designed, but instead it was developed organically.
That's the story of PHP. There is no consistency anywhere.
You have a function named
htmlentities()
to encode and
html_entity_decode()
to decode.
Seriously, WTF???
Looks like people there cannot stick to a convention.
There is a core function named
strcmp()
WITHOUT
underscore, and one named
str_replace()
WITH
underscore. Speaking about that one, have a look to its prototype:
str_replace(search, replace, subject [, count ] )
... versus:
str_split(subject [, split_length ] )
Yes, that's another gotcha: the first one want the subject string to be its third argument, the second want it to be its first argument. Ugly.
There are plenty of examples of inconsistencies in PHP, and after years of programming with it, it still happens that I forget the correct order for a particular function.
Also PHP does
NOT
support unicode natively,
you have to rely on a very small subset of the string manipulation function
prefixed by
mb_*
. When I started using PHP, most of those functions were missing, and it's still painful to do unicode aware code. This is probably the PHP greatest weakness. Almost all websites are using
UTF-8
now.
There was a failed attempt to upgrade PHP's core with unicode,
PHP 6, but it was miserably aborted.
Finally, PHP has errors
AND
exceptions.
Silly.
Also I'm not going to list all of PHP's failures here, there are dozens of websites doing that. For example
PHP: a fractal of bad design
is a really well-documented article.
So there are two kinds of people: people that can cooperate with a weird but capable language, and perfectionist people that will hate it from day one.
A short story of modern Javascript
The Javascript language has its haters too.
However,
most of the arguments against it exists because Javascript is the most misunderstood language.
For decades, not a single book was accurate or written by someone who has a clue about the language very nature, except Douglas Crockford.
Worst:
Internet Explorer totally distorted it for years, and we all know what the harm Microsoft can do when it has decided to totally break any living standard for the sake of its monopoly...
Programmers exposed to Javascript back in the IE 5.5 and IE 6 days have been totally traumatized.
And I was one of those. By the way, Microsoft's
JScript
is
*NOT*
Javascript, but sadly no one cares about that.
Then Javascript had a second live:
-
JQuery helped to abstract away browser's incompatibilities.
-
Google Chrome appears, rapidly conquers its share of market, and initiate a browser-war that Microsoft cannot win anymore, leading to the JS engine race we all know:
suddenly Javascript becomes lightning fast!
Also Internet Explorer was forced to follow the standards, or it would lost even more marketshare.
-
Mozilla and Google has done a huge work to push the language forward:
Google is usually the innovative guy and Mozilla the perfectionist that polish things and improve the spec
before
its standardization.
-
Thanks to the V8 speed, Javascript becomes an option for server-side scripting: Node.js appears and the ecosystem is growing up really fast.
Node.js enforces the RequireJS spec and the last major gotcha of Javascript is finally gone: global variable leaks. Now Javascript is modular, and is fully capable to handle big projects.
Npm is probably the better package manager in the world and solves dependency hell in an elegant way.
The Javascript language
Javascript is a dynamic language, featuring a
prototype-based OOP
.
It has dynamic typing, so
duck typing
is really common here.
Almost everything in Javascript is an object.
Object literal are common too, and more than often they are used to pass named parameter to a function. Object are basically a hashmap, eventually a prototype chain (also useful for inheritance), and since functions are
first-class citizens
that make them methods. Finally, Javascript has
closures.
Javascript is event-driven, so callbacks are used everywhere.
The beauty of Javascript is its simplicity and its expressiveness.
With only few keywords, almost any constructs are possible.
Common criticisms
People often criticizes the Javascript object model. Some are claiming that it is a
Procedural
language, not an
OOP
language.
They are wrong.
Usually, people are confusing
OOP
with
Class-based OOP. Javascript is a
Prototype-based OOP language.
See the wikipedia page about
programming paradigm
and about
prototype-based programming.
There is a
very interesting comment
written by
@Plynx, explaining the benefits of the Javascript OOP, and the differences between class-based OOP. The comment is very long, detailed and well-written, this quote is just a small part of it:
I should probably say a few words about encapsulation, since it's often cited by object oriented programmers as being a very important aspect of programming.
The ability to hide data and functionality is present in Javascript in the form of closures, but they are rarely used that way, and the history of encapsulation should make it clear why. Earlier I mentioned namespace pollution as one of the key problems in early structured programming languages. Modern taboo against global variables flows in part from the problems programmers had when name collisions would occur after the merge of disparate codebases. Additionally the concept of the object as an API, and the need to subclass in order to extend functionality while preserving type compatibility, led to the creation of the access qualifiers in OOP. Initially it was thought that this method of disallowing unintended use of classes would be a boon to group development, but a number of studies have shown that it did not improve productivity.
The primary benefit of encapsulated classes was the fact that they created namespaces, now a headline feature in class-based languages. Namespaces produce the benefit of not having name collisions while also documenting the intended use of a class, without hamstringing future development by restricting the possibility of unforeseen useful code sharing by prematurely disallowing it. In Javascript, every object being a dynamic associative array makes every {} a namespace (even more name control is possible through module.exports in Node). Namespaces are generally a superior approach to encapsulation, preserving the benefits without dealing with the grueling problems of strict access control to portions of classes in class-based languages.
People previously exposed to
class-based OOP
will often found Javascript reluctant: no classes, no private members... Javascript is fully capable of that, but you have to do it by yourself: a constructor is just a mere function that can create object, and used in conjunction with prototypes achieve the same thing that classes. Private members are possible through closures. That doesn't means you need to code more to get that, and in fact you have to code less, that just means there is no
class
or
private
keyword.
However you can do
more, if you want.
A prototype is nothing more than a regular object: you can mutate it and all
instances
created by that prototype are mutated. No class-based language is able do to that at runtime.
Anyway, it's worth noting that there is no need for private members at all, in a dynamic language. Also there is no inherent reason to code a complex class hierarchy, that would lead to over-engineering,
lasagna code
or worst:
spaghetti code. There is no need for such overhead in Javascript.
Good Javascript code embraces
the KISS principle. KISS projects advance at a faster pace, they are robust, clean, healthy and easy to maintain.
Also, Javascript
has
some real gotcha:
-
arguments
is not an
Array
, and it's boring to type
Array.prototype.slice.call( arguments )
everytime you want Array features...
-
+
operator can mix string and numbers: it performs concatenation
or
addition.
-
you can't
easily
inherit from builtin objects (e.g.
Array
)
-
typeof null === 'object'
this one really sucks... it's the thing I hate the most about Javascript... The workaround is easy, still, I hate to type
if ( myVar && typeof myVar === 'object' )
all days... And it won't be fixed :'(
-
UCS-2
unicode encoding instead of
UTF-16...
In fact Javascript exposes characters as
UCS-2 with surrogate pairs.
E.g. a single chinese unicode character takes 2 characters in a Javascript string.
-
automatic semicolon insertion: semicolon are not mandatory to end a statement, semicolon can be automatically inserted at the end of the line. A semicolon can be inserted by the parser where it's not intended by the coder, e.g. if the return keyword is followed by a new line.
Also people usually adds
NaN
to the list, because
NaN
stands for
Not a Number
and still
typeof NaN === 'number'
, and because
NaN !== NaN
. However, there are
wrong, actually
NaN behaves just like it should. Really. Just read
Javascript NaN Demystified
if you don't believe me.
Let's compare them!
Where PHP wins:
-
PHP is very classic: if you come from C/C++/Java & co, you will find similar concept.
-
Easiest to grasp: partly in consequence of the previous point,
you will be able to code in PHP in no time. You will be able to code in Javascript quickly too, but your code will be crappy even if you have some solid knowledge in other languages.
You will have to realize that Javascript does not work the way you are used to, and you will have to change your habits.
-
PHP has destructors, Javascript doesn't... sometime I'm missing them.
Where Javascript/Node.js wins
-
Unicode support: UCS-2 is suboptimal, however it's still far better than no support at all.
-
Isomorphic Javascript
: you can share modules between your server-side Node.js codebase and your browser-side codebase.
Browserify
can help you in the process.
-
Less boilerplate code.
-
Faster: consequence of the previous point: it's possible to write application faster,
and to achieve great things with a smaller codebase.
-
Easiest to maintain: code above the average is easiest to maintain in Javascript than in PHP. Also please note that it is possible to code total crap in Javascript, so this does
*NOT*
apply to code below the average. PHP can be very crappy too, but its paradigm drive the programmer a bit more.
-
Cleaner core:
no global namespace pollution here, the language is rather consistent, and almost every core features are OO.
-
Expressiveness and flexibility: Javascript is one of the most expressive language, and win this battle hands down.
-
Javascript is event-driven, dealing with I/O is way faster and easier, internet is more and more about realtime and Node.js is a strong player in that area.
-
Websocket: consequence of the previous point, Javascript is
*THE*
language of choice if you want to deal with websocket.
-
Freedom: you build your own server or micro-service, so everything is possible, you are not tied to the PHP paradigm.
-
Evolution: the Javascript language evolves quickly and far more openly. New features have been well weighted. Some quirks of the past will remain for the sake of backward compatibility, but at least new additions will be clean. On the contrary PHP is not really open, few peoples have total power on the future of the language and are not listening to criticism at all.
Conclusion
As you can see, Javascript scored more points than PHP. And that's not going to change anytime soon.
In fact PHP is evolving too. Some features were missing and they were added. But not in a sane way.
The path of PHP is wrong.
So let's finish the talk with two angular stones of PHP 5 that allow it to be framework-compliant:
autoloading and namespace.
When
autoloading
was included, I was like
“Nice! This is really useful and solves a lot of trouble I had in the past”. And that's right: PHP is greater with
autoloading
than without.
However, looking backward, it appears that
autoloading
was an infamous monstrosity.
There was a problem, but it was fixed in the badest possible way. It is really hacky.
It was combined later with
namespaces
to avoid massive global scope pollution by third-parties. In a way, it opened the road to framework interoperabilities,
but since it does not solve the whole thing, the frameworks had to do what PHP should had done by itself.
It leads to a consortium of frameworks and those awkward
PSR-x
specs. But shitty PHP-frameworks will be explored in the next article of this series.
It's worth noting PHP's namespace syntax uses backslashes as separators. That's very unusual and I don't like it.
That does not fix the main issue with PHP:
require()
and
include()
(and therefore
autoloading) in PHP works the same way the
#include
preprocessor directive works in C/C++: it's just a kind of runtime copy-paste of file to include into the parent file.
Therefore, it is totally leaky by design!
Now that I'm a Node.js developper, it's even more evident that PHP was wrong.
Node.js solves the dependency hell in the most elegant way: you require a lib (i.e. a module) into a variable. A Node.js module returns (i.e.
exports)
something
into the caller's variable.
Usually a module either exports a function or an object containing a collection of functions.
Okey, an example is worth thousand words, let's say we have a function called
toto()
. Later we found out a wonderful third party lib, but unfortunately its name is
"toto"
too. No problem, let's load the module into the
"moduleToto"
variable:
var toto = function() {
// my code
}
// load toto into moduletoto
var moduletoto = require( 'toto' ) ;
// use the third party lib
moduletoto.makesomethingawesome() ;
Nothing leaks outside of a module.
No pollution.
Furthermore, in Node.js proper namespaces would be useless because they already exist the Javascript way: you just have to put submodules into properties of the main module.
So simple.
So KISS.
That's why I like Javascript.