Node.js for PHP programmers #2: Modules, Packages, And The Strawberry House

PHP knows how to group classes under a common namespace, and to create redistributable packages using PEAR. Node.js is also very good at organizing code into modular and reusable sets, but there are key differences. I'll explain them shortly, but before I'd like to talk about dolls.Node.js for PHP programmers #2: Modules, Packages, And The Strawberry House

The Doll Problem

My 4-year old daughter was recently offered a second-hand doll set, including 4 dolls, various clothes, furniture, a pony, and a strawberry house. She loves to dress and undress the dolls, and I'm glad to see her learning how to do that perfectly - much better than she knows how to dress herself.

The problem is that she doesn't know how to put the clothes away when she finishes playing, just like she leaves her scarf, sweater and cap on the floor when she comes back home. So it's my sad duty to put the doll clothes away in the strawberry house, and this is a pain. You see, each piece of clothing must be neatly folded and put away in a very specific place, otherwise "it's not good". So the pink socks must go into the bedroom closet in the strawberry house, but not the pink dress - no, this one must go into the entrance chest.

If you want my opinion, folding and putting doll clothes away is so boring that this task should be given to a computer. My daughter would probably never understand it, but I'm sure you will.

Including Scripts in PHP and Node.js

PHP knows how to categorize classes using namespaces. Here is an example:

PHP namespaces are a very simple feature. At compile time, the PHP parser prefixes all the class names in the file using the declared namespace. So Sock (the class name) becomes House\Bedroom\Closet\Sock (the fully qualified class name) - it's just string manipulation. It's enough to prevent name collision, but it often makes the code harder to read than it really should:

The Node.js equivalent of the Sock class declarations is straightforward. In JavaScript, classes are functions, and methods are properties of the function object's prototype. This may be disturbing at first, but you will quickly get used to it.

The last line is more specific to Node.js. Node provides a global object called exports. The script adds the newly defined Sock class as a property of this exports object. In practice, this last line "exports" the class to the outside, and defines the public API of the script.

To import this exports object into another variable, Node provides the require() function:

Although the code looks similar to the PHP version, what happens here is a little different. Node's require() function does not just load and execute the socks.js code directly. Instead, it returns a copy of the exports object defined in the socks.js script.

Tip: Node doesn't need the .js ending in the file path passed as parameter to require(). Node finds the script even if you just call require('./house/bedroom/closet/sock'). The suffix will be omitted in further examples.

require Is The Gate To The Module System

To be fair, exports is not really a global object. It's local to a Node module. And what's a module? In short, it's a closure. Here is what the call to require actually does behind the curtain:

require encapsulates the sock.js code into a closure, and executes it using the exports object as a parameter. That's why exports is said to be a pseudoglobal: it is seen as a global variable from within a module, but in fact it is local to this module. So all the variables defined in a module (like accepted_colors and Sock) are isolated and don't pollute the global namespace. Only the properties added to the exports parameter make it to the outside:

The accepted_colors variable is therefore private and cannot be accessed by any outside script that requires the sock module. You can imagine how this can be used to create private classes, a concept nowhere to be found in PHP.

Node.js isn't at the origin of the module concept. It's part of an initiative called CommonJS, and the CommonJS "module" feature has several implementations. Node.js offers one of them, adds some syntactic sugar and a few bonus features.

Modules Are Smart Objects

There is one major difference between the PHP and the JavaScript versions of the doll socks example. In JavaScript, sock is just the name of the variable storing the require() return value. This "namespace" is nowhere to be found in the original sock.js script. In other terms, in JavaScript it's the caller who adds the namespace, while in PHP the callee must be namespaced.

That makes aliasing trivial in Node:

This is the equivalent of the use ... as statement in PHP:

By the way, if a module exports just a single class, you may want to use an alternative exporting method called module.exports:

Where does that module object come from? Just like exports, it is passed to the module as a pseudoglobal. To be completely fair, the result of a call to require('sock') looks more like the following:

Yes, that's an anonymous function calling itself. For an average PHP developer, this may be looking like voodoo, but the truth is to be found farther East.

Node's Modules Are Matryoshka Dolls

You know these Russian nesting dolls called Matryoshka dolls? Well, Node modules are a bit like that. Small modules can nest inside larger modules:

You can require a module and reexport it. And since the require() function is in fact a pseudoglobal, it executes in the context (and using the file path) of the current module. That makes nesting of modules extremely easy, without necessarily using long fully qualified class names as in PHP. Besides, it keeps the code readable, while PHP code following the PSR-0 standard is harder to read due to namespaces matching the directory structure.

There is much more to tell about Node's module system. But doll clothes need to be put away. Node.js module documentation is a must read if you really need to know more.

The Doll House

Once every cloth is neatly folded at the right place, the strawberry doll house can be closed. It has a nice handle, so I could easily give the strawberry house to another kid to freak their dad out. The same goes for libraries: you can package several scripts together, and distribute the result across your company, or the Internet.

PHP's doll house market is called PEAR. It should be the default distribution method used by library developers, but it's more and more replaced by git clone or composer. That's probably because PEAR has many drawbacks. First, it installs libraries user- (or system-) wide, which means that all projects must share the same version of a given library. Second, creating PEAR packages is a pain due to a very verbose XML package description format. Third, publishing packages is not an easy task (having your own package registered on the main PEAR channel is heavy, and hosting your own channel is heavy, too). Last, many PEAR packages have not been updated for a while - that's not the preferred package registry anymore.

Node, on the other hand, comes with a very powerful Node Package Manager. npm is both a distribution utility and the central repository for Node public packages. Check the list of available packages (about 7000 packages available as of writing this post) in the node registry.

If you want to publish your own package for other developers using npm, you don't need anybody's permission, you don't even need to describe all the files in your package. You just need a simple package.json at the root of the package looking like the following:

The npm JSON package description format allows for much more metadata, but these four lines are enough to publish the package to the node public registry. To do so, just call:

npm publish .

Of course, you can also choose to publish a package only to your own private registry.

To install a public node package, just call npm install:

npm install my-little-pony

This downloads and installs the my-little-pony package, together with all its dependencies, under the node_modules/ subdirectory, under the current path.

Even better, if you define your own list of dependencies in the package.json file, npm will download and install all of them for you when you call:

npm install

Multiple Modules and Package versions

The greatest thing about both the module and package system of Node.js is that it solves version conflicts in the most elegant way: by allowing several versions of a module or package in the same application.

Let's say you use the strawberry-house package AND the girl-toys packages in a project. girl-toys itselfs depends on the strawberry-house package, and there are chances that it doesn't require the same version than the one you're using directly.

It doesn't matter: npm will install the girl-toys dependencies in its own directory, and let you use your own version:

app.js                   // your own app
node_modules/
  strawberry-house/      // the one you use directly
  girl-toys/
    node_modules/
      strawberry-house/  // the one used by girl-toys
      my-little-pony/

With Node's encapsulated module system, you'll never have to worry about version conflicts anymore.

Conclusion

I learned how to fold doll clothes, I'm sure you'll learn how to use Node's powerful module system. Both are easy, and programmers tend to have more fun with the latter. As compared to the equivalent features in PHP, Node modules and packages feel very refreshing. That's probably why the Node community is so active, and the number of available packages is growing so rapidly.

Also in this series: Node.js for PHP programmers #1: Event-driven Programming... and Pasta and Node.js for #PHP Programmers #3: Exceptions and Errors.

Published on 07 Feb 2012 with tags development JavaScript NodeJS php

comments powered by Disqus