36
Node.js for PHP developers for CampJS IV by Andrew Eddie

Node.js for PHP developers

Embed Size (px)

DESCRIPTION

A talk by Andrew Eddie to possibly help developers experienced with PHP and similar languages to make a more gentle splash in the deep-end of Node.js.

Citation preview

Page 1: Node.js for PHP developers

Node.js for PHP developers

for CampJS IV

by Andrew Eddie

Page 2: Node.js for PHP developers

@AndrewEddie

• Civil Engineer (1990) turned Software Engineer (2000)

• Discovered Basic early 80's - nerd ever since

• Cut teeth on C and C++ (late 90's vintage)

• PHP Open Source contributor

• Node acolyte

Page 3: Node.js for PHP developers
Page 4: Node.js for PHP developers

JavaScript

• Was born in 1995 (same as PHP)

• Is ECMAScript

• Shares a mostly familiar C-style syntax

• Is not Java

• Is not CoffeeScript et al

Page 5: Node.js for PHP developers

Node.js

• It's just server-side JavaScript (it is the server)

• V8 - very light core

• Single thread event loop

• Package management via NPM

• No real equivalent to things like SPL or PHP-FIG

Page 6: Node.js for PHP developers

Documentation

• https://developer.mozilla.org/en-

US/docs/Web/JavaScript

• http://nodejs.org/documentation/

• Individual modules/packages

• http://kapeli.com/dash

Page 7: Node.js for PHP developers

Interactive command line / REPL

$ php -a

php > echo "Hello World!\n";;

Hello World!

php >

$ node

> console.log('Hello World');

Hello World

undefined

>

Page 8: Node.js for PHP developers

Primitive value differences

// PHP

// * booleans

// * integers

// * floating point numbers

// * strings

// * arrays

// * objects

// * resources

// * null

// * callbacks

// JavaScript

// * boolean

// (number)

// * number

// * string

// (object)

// * object

//

// * null

// (function, which is an object)

Page 9: Node.js for PHP developers

Variable differences

<?php

// PHP

$minecraft = '1.8.1-pre3';

$spawnX = -77;

$spawnY = 63;

$spawnZ = 241;

// JavaScript

seed = -6623756275123996544;

var spawnX = -77;

var spawnY = 63,

spawnZ = 241;

var $biome = 'Savanah';

Page 10: Node.js for PHP developers

Operator differences

// PHP

$number = 1 + 2;

$string = 'mega' . 'taiga';

$string .= ' biome';

1 && 2 && 3; // true

1 && 3 && 0; // false

$perPage || 10; // true

// JavaScript

var number = 1 + 2;

var string = 'extreme' + ' hills';

string += ' biome';

1 && 3 && 2; // 2

1 && 3 && 0; // 0

perPage || 10; // 10

Page 11: Node.js for PHP developers

Falsy differences

// PHP

false;

0;

"";

"0"

null;

$x is undefined

// NAN is truthy (double), need is_nan()

array(); // Empty array

// JavaScript

false;

0;

"";

// "0" is truthy!

null;

undefined;

NaN;

// [] is truthy!

Page 12: Node.js for PHP developers

Array differences

// PHP 5.4+

$recipe = ['water', 'nether wart'];

$recipe[] = 'glass bottle';

// array_push($recipe, 'another one');

$array = new ArrayObject($recipe);

$array.count(); // 3

array_keys($array);

foreach ($array as $index => $value) {

echo "\narray[$index] = $value";

}

// Note PHP < 5.4

$recipe = array('water', 'nether wart');

// JavaScript

var recipe = ['x', 'y', 'z'];

recipe.push('4th dimension');

recipe.length; // 3 (are you sure?)

recipe.keys();

recipe.forEach(function (value, index) {

console.log(index + '=' + value);

});

Page 13: Node.js for PHP developers

Associative arrays

// PHP

$inventory = [

'pick' => 'stone',

'sword' => 'diamond',

'axe' => 'iron'

];

// JavaScript

var inventory = {

pick: 'stone',

sword: 'diamond',

axe: 'iron'

};

Page 14: Node.js for PHP developers

Object differences

// PHP

$inventory = new stdClass;

$inventory->pick = 'stone';

$inventory->sword = 'diamond';

$inventory->axe = 'iron';

// Alternatively

$inventory = (object)[

'pick' => 'stone',

'sword' => 'diamond',

'axe' => 'iron'

];

echo $inventory->pick;

$axe = 'axe';

echo $inventory->$axe;

// JavaScript

var inventory = {

pick: 'stone',

sword: 'diamond',

axe: 'iron'

};

console.log(inventory.pick);

console.log(inventory['axe']);

Page 15: Node.js for PHP developers

The same

• if

• while

• do-while

• for

• function (or closure) declaration

Page 16: Node.js for PHP developers

Switch

// PHP

switch ("") {

case false:

echo 'It is false';

break;

case "":

echo 'Empty string';

break;

default:

echo 'Did not match';

}

// It is false

// Loose == comparison!

// JavaScript

switch ("") {

case false:

console.log('It is false');

break;

case "":

console.log('Empty string');

break;

default:

console.log('Did not match');

}

// Empty string

// Strict === comparison

Page 17: Node.js for PHP developers

Synchronous try-catch

// PHP

try {

throw new Exception('Bad req', 400);

}

catch (Exception $e) {

echo $e->getMessage();

echo $e->getCode();

echo $e->getTraceAsString();

}

// JavaScript

try {

throw new Error('Bad req');

}

catch (err) {

console.log(err.message);

// No native 'code' support.

console.log(err.stack);

}

Page 18: Node.js for PHP developers

foreach / for-in

// PHP

foreach ($objOrArr as $k => $v) {

echo "Key is $k\n";

echo "- value is $v\n";

}

// JavaScript

for (k in object) {

console.log("Key is %s", k);

console.log("- value is %s",

object[k]);

}

Page 19: Node.js for PHP developers

Function defaults

// PHP

function fetch($page, $perPage = 10) {

// ...

return $page * perPage;

}

php > fetch();

Warning: Missing argument 1 for fetch(), called in php

shell code on line 1 and defined in php shell code on

line 1

// JavaScript

function fetch(page, perPage) {

perPage = perPage || 10;

return page * perPage;

}

> fetch();

NaN

>

// Workaround?

function fetch(page, perPage) {

if (page === undefined) {

throw Error('Page missing');

}

perPage = perPage || 10;

return page * perPage;

}

Page 20: Node.js for PHP developers

Invoking functions

// PHP

function getDamage($weapon, $level) {

// ...

return $damage;

}

$damage = getDamage('axe', 1);

call_user_func('getDamage', 'axe', 1);

call_user_func_array(

'getDamage',

['axe', 1]

);

// JavaScript

function getDamage(weapon, level) {

// ...

return damage;

}

var damage = getDamage('axe', 1);

getDamage.call(null, 'axe', 1);

getDamage.apply(null, ['axe', 1]);

Page 21: Node.js for PHP developers

Closures

// PHP

$mineBlock = function ($block) {

// ...

return $item;

};

$item = $mineBlock('diamond ore');

// JavaScript

var mineBlock = function (block) {

// ...

return item;

};

var item = mineBlock('diamond ore');

Page 22: Node.js for PHP developers

Function Scope

// PHP

// Global if in the main file.

$sky = 'blue';

function night() {

$sky = 'black';

}

night();

echo $sky; // blue

// JavaScript

// Always global.

sky = 'blue';

function night() {

sky = 'black';

}

night();

console.log(sky); // black

Page 23: Node.js for PHP developers

Function Scope - PHP equivalent to JavaScript

// PHP

// Global if in the main file.

$sky = 'blue';

function night() {

global $sky;

$sky = 'black';

}

night();

echo $sky; // black

// JavaScript

// Always global.

sky = 'blue';

function night() {

sky = 'black';

}

night();

console.log(sky); // black

Page 24: Node.js for PHP developers

Function Scope - JavaScript equivalent to PHP

// PHP

// Global if in the main file.

$sky = 'blue';

function night() {

$sky = 'black';

}

night();

echo $sky; // blue

// JavaScript

// Always local.

var sky = 'blue';

function night() {

var sky = 'black';

}

night();

console.log(sky); // blue

Page 25: Node.js for PHP developers

Classes?

// PHP

class Block {

public $type;

public function __construct($type) {

$this->type = $type;

}

public function getType() {

return $this->type;

}

}

$sand = new Block('sand');

// JavaScript

function Block(type) {

this.type = type;

}

Block.prototype.getType = function () {

return this.type;

}

var dirt = new Block('dirt');

Page 26: Node.js for PHP developers

"Classes" in JavaScript

• Constructors are just named functions

• Functions called with `new` return `this`

• `new` allows prototyping to work

• Upper CamelCase function names by convention

• No native equivalent to `protected`

• True `private` is possible but awkward

Page 27: Node.js for PHP developers

Inheritance - JavaScript

// PHP

class DiamondOre extends Block {

function __construct() {

this.type = 'DiamondOre';

}

}

// JavaScript

function DiamondOre() {

// Remember the original constructor

// back a slide or two took a type.

Block.call(this, 'DiamondOre');

}

DiamondOre.prototype =

Object.create(Block.prototype);

DiamondOre.prototype.constructor =

Block;

Page 28: Node.js for PHP developers

Inheritance - Node

// PHP

class IronOre extends Block {

function __construct() {

parent::__construct('IronOre');

}

function getType() {

return 'Unsmelted'

. parent::getType();

}

}

// JavaScript

var util = require('util');

function IronOre() {

Block.call(this, 'IronOre');

}

util.inherits(IronOre, Block);

IronOre.prototype.getType = function (){

return 'Unsmelted'

+ super_.getType();

}

Page 29: Node.js for PHP developers

Class closure scope - public example

// PHP

class Tool {

public $max = 5;

function register($container) {

// Pre PHP 5.4

$self = $this;

$f = function($bag) use ($self){

return count($bag)

< $self->max);

};

$container->register($f);

}

}

// JavaScript

function Tool() {

this.max = 5;

}

Tool.prototype.register = function($c){

var self = this;

var f = function (bag) {

return bag.length < self.max;

}

c.register(f);

}

Page 30: Node.js for PHP developers

Class closure scope - private example

// PHP

class Tool {

private $max = 5;

function register($container) {

// Pre PHP 5.4

$self = $this;

$f = function($bag) use ($self){

return count($bag)

< $self->max);

};

$container->register($f);

}

}

// Node module

// "max" is now private to Tool.

var max = 5;

Tool.prototype.register = function($c){

var self = this;

var f = function (bag) {

return bag.length < max;

}

c.register(f);

}

Page 31: Node.js for PHP developers

Modules

• Modules sort of equate to "class"

• Sand-boxed scope

• Returns module.exports

Page 32: Node.js for PHP developers

Modules - conceptual equivalence

// PHP

root

|- Game

| `- Block.php

|- vendor

| |- composer

| |- monolog

| `- autoload.php

|- index.php

`- package.json

----------

<?php

require './vendor/autoload.php';

use Monolog\Logger;

use Game\Block;

$log = new Logger('name');

// JavaScript

root

|- lib

| `- game

| `- index.js

|- node_modules

| `- winston

|- app.js

`- package.json

----------

// Conceptual equivalent

var winston = require('winston');

var Game = require('./lib/game');

var Block = Game.Block;

var block = new Block('DiamondOre');

Page 33: Node.js for PHP developers

Some popular modules

• Logging - Winston

• Promises - Bluebird, Q

• Utility classes - Lodash

• Web serving - Express

• ORM - Waterline, JugglingDB

• MVC/ADR - Build your own

Page 34: Node.js for PHP developers

Documentation, Testing and Build Tools

• npm (vs Composer or <cough>PEAR</cough>)

• JSDoc (vs phpDocumentor)

• Mocha (vs PHPUnit) { ui: 'exports' }

• Sinon (object mocking)

• Nock (request mocking)

• Frisby/Supertest (request functional testing)

• Istanbul (code coverage)

• Grunt (vs Phing)

Page 35: Node.js for PHP developers

What do to with non-public scope?

• True private - hard to test

• Could use the old PEAR underscore prefix

• Could reference them via a faux value

• Could use @private in the DocBlock

Page 36: Node.js for PHP developers

Thank you - Questions?

eddify.me

twitter.com/AndrewEddie

slideshare.net/AndrewEddie

delicious.com/eddieajau/node.js