Upgrade to Pro — share decks privately, control downloads, hide ads and more …

JavaScripting for the PHP Developer in 2012

JavaScripting for the PHP Developer in 2012

The modern day web developer is presented with possibilities the developers of 2005 would salivate over. In this session we'll look at some JavaScript tools that will simplify your web development life by reducing the complexity of your PHP backend, increasing the rich user interface presented in the browser, as well as redundancy in your frontend and backend code.

Jeff Carouth

October 24, 2012
Tweet

More Decks by Jeff Carouth

Other Decks in Programming

Transcript

  1. JavaScripting for the
    PHP Developer in 2012
    this is not the JavaScript from 1999
    Jeff Carouth ZendCon 2012

    View full-size slide

  2. Jeff Carouth
    tweets jcarouth
    blogs http://carouth.com
    checks [email protected]
    works

    View full-size slide

  3. JavaScript Basics

    View full-size slide

  4. Arrays
    array();
    []; //PHP 5.4+
    array(1, 2, 3, 4);
    array(1, "foo", new stdClass());
    array("foo" => "bar", "fizz" => "buzz");

    View full-size slide

  5. Arrays
    array();
    []; //PHP 5.4+
    array(1, 2, 3, 4);
    array(1, "foo", new stdClass());
    array("foo" => "bar", "fizz" => "buzz");
    []; // new Array();
    [1, 2, 3, 4];
    [1, "foo", {}];
    ["foo": "bar", "fizz": "buzz"]; //ERROR

    View full-size slide

  6. Arrays
    array();
    []; //PHP 5.4+
    array(1, 2, 3, 4);
    array(1, "foo", new stdClass());
    array("foo" => "bar", "fizz" => "buzz");
    []; // new Array();
    [1, 2, 3, 4];
    [1, "foo", {}];
    ["foo": "bar", "fizz": "buzz"]; //ERROR
    {"foo": "bar", "fizz": "buzz"}; //NOT an array

    View full-size slide

  7. Arrays
    typeof []; // 'object'
    typeof new Array(); // 'object'
    [3]; // arr.length = 1
    new Array(3); // arr.length = 3

    View full-size slide

  8. Objects
    but NOT
    Classes
    Prototypes

    View full-size slide

  9. class Car
    {
    private $make;
    private $model;
    private $year;
    public function __construct($make, $model, $year)
    {
    $this->make = $make;
    $this->model = $model;
    $this->year = $year;
    }
    // could use __toString()
    public function toString()
    {
    return $this->year." ".$this->make." ".$this->model;
    }
    }
    $myFirstCar = new Car('Acura', 'Integra', 1990);
    print $myFirstCar->toString();
    // Result: ‘1990 Acura Integra’

    View full-size slide

  10. function Car(make, model, year) {
    this.make = make;
    this.model = model;
    this.year = year;
    this.toString = function() {
    return this.year + " " + this.make + " " + this.model;
    }
    }
    var myFirstCar = new Car('Acura', 'Integra', 1990);
    var myNewCar = new Car('Dodge', 'Charger', 2009);
    myFirstCar.toString();
    // Result: ‘1990 Acura Integra’
    myNewCar.toString();
    // Result: ‘2009 Dodge Charger’

    View full-size slide

  11. Checking Type
    gettype($myFirstCar); // object
    $myFirstCar instanceof Car; // true
    get_class($myFirstCar); // Car
    typeof myFirstCar; // 'object'
    myFirstCar instanceof Car; // true
    myFirstCar.constuctor; // Car
    php
    JavaScript

    View full-size slide

  12. Prototypal Inheritance
    Warning: Here be dragons…at first.

    View full-size slide

  13. Object Methods Via the Prototype
    function Car(make, model, year) {
    this.make = make;
    this.model = model;
    this.year = year;
    this.toString = function() {
    return this.year + " " + this.make + " " + this.model;
    }
    }

    View full-size slide

  14. Object Methods Via the Prototype
    function Car(make, model, year) {
    this.make = make;
    this.model = model;
    this.year = year;
    this.toString = function() {
    return this.year + " " + this.make + " " + this.model;
    }
    }
    function Car(make, model, year) {
    this.make = make;
    this.model = model;
    this.year = year;
    }
    Car.prototype.toString = function() {
    return this.year + " " + this.make + " " + this.model;
    }

    View full-size slide

  15. function Car(make, model, year) {
    this.make = make;
    this.model = model;
    this.year = year;
    this.toString = function() {
    return this.year + " " + this.make + " " + this.model;
    }
    }
    var aCar = new Car('Saturn', 'Vue', 2007);
    var anotherCar = new Car('Ford', 'F150', '2003');
    aCar.toString(); // '2007 Saturn Vue'
    anotherCar.toString(); // '2003 Ford F150'
    aCar.toString = function() {
    return '2013 BMW 335is Convertible';
    };
    aCar.toString(); // '2013 BMW 335is Convertible'
    anotherCar.toString(); // '2003 Ford F150'

    View full-size slide

  16. function Car(make, model, year) {
    this.make = make;
    this.model = model;
    this.year = year;
    }
    Car.prototype.toString = function() {
    return this.year + " " + this.make + " " + this.model;
    }
    var aCar = new Car('Saturn', 'Vue', 2007);
    var anotherCar = new Car('Ford', 'F150', '2003');
    aCar.toString(); // '2007 Saturn Vue'
    anotherCar.toString(); // '2003 Ford F150'
    Car.prototype.toString = function() {
    return '2013 BMW 335is Convertible';
    };
    aCar.toString(); // '2013 BMW 335is Convertible'
    anotherCar.toString(); // '2013 BMW 335is Convertible'

    View full-size slide

  17. class Dad extends Person
    {
    public function __construct($firstName)
    {
    $this->familyName = 'Carouth';
    parent::__construct($firstName);
    }
    }
    class Son extends Dad
    {
    }
    $son = new Son('Jeff');
    print $son->familyName; // 'Carouth'

    View full-size slide

  18. var Dad = function() {
    this.familyName = 'Carouth';
    };
    var Son = function(firstName) {
    this.firstName = firstName;
    };
    Son.prototype = new Dad();
    Son.prototype.constructor = Son;
    var jeff = new Son('Jeff');
    jeff.familyName; // 'Carouth'
    jeff instanceof Son; // true
    jeff instanceof Dad; // true

    View full-size slide

  19. Namespaces
    Easy in PHP 5.3+
    Easy enough in JavaScript

    View full-size slide

  20. namespace Foo;
    class Car
    {
    public function __construct($make, $model, $year)
    {
    // ...snip...
    }
    // ...snip...
    }
    //someotherfile.php
    $myCar = new Foo\Car('Toyota', 'Prius', '2011');

    View full-size slide

  21. var Foo = Foo || {};
    Foo.Car = function(make, model, year) {
    // ...snip..
    };
    var myCar = new Foo.Car('Toyota', 'Prius', '2011');

    View full-size slide

  22. The Module Pattern

    View full-size slide

  23. var Car = (function() {
    var Constructor;
    Constructor = function(make, model, year) {
    this.make = make;
    this.model = model;
    this.year = year;
    }
    Constructor.prototype.toString = function() {
    return this.year + " " + this.make + " " + this.model;
    }
    return Constructor;
    }());

    View full-size slide

  24. var Car = (function() {
    var Constructor;
    Constructor = function(make, model, year) {
    this.make = make;
    this.model = model;
    this.year = year;
    }
    Constructor.prototype.toString = function() {
    return this.year + " " + this.make + " " + this.model;
    }
    return Constructor;
    }());
    (function() {
    }());

    View full-size slide

  25. var Car = (function() {
    var Constructor;
    Constructor = function(make, model, year) {
    this.make = make;
    this.model = model;
    this.year = year;
    }
    Constructor.prototype.toString = function() {
    return this.year + " " + this.make + " " + this.model;
    }
    return Constructor;
    }());
    var Car =
    var Constructor;
    return Constructor;

    View full-size slide

  26. var Car = (function($) {
    var Constructor;
    Constructor = function(make, model, year) {
    this.make = make;
    this.model = model;
    this.year = year;
    }
    Constructor.prototype.toString = function() {
    return this.year + " " + this.make + " " + this.model;
    }
    return Constructor;
    }(jQuery));
    Dependencies

    View full-size slide

  27. Extension
    myCar.beep(); //undefined
    Car = (function(Car) {
    Car.prototype.beep = function() {
    return 'Beep';
    };
    return Car;
    }(Car));
    myCar.beep(); // 'Beep'

    View full-size slide

  28. Information Hiding
    A.K.A. private properties

    View full-size slide

  29. var Car = (function() {
    var started = false;
    var Constructor;
    Constructor = function(make, model, year) { /* snip */ };
    Constructor.prototype = {
    constructor: Constructor,
    toString: function() { /* snip */ },
    start: function() {
    if (!started) {
    started = true;
    }
    },
    isRunning: function() {
    return started === true;
    }
    };
    return Constructor;
    })();

    View full-size slide

  30. var myCar = new Car('BMW', '335is Convertible', 2013);
    myCar.isRunning(); // false
    myCar.started; // undefined
    myCar.start();
    myCar.isRunning(); // true

    View full-size slide

  31. require.js
    file
    and
    module
    loader

    View full-size slide




  32. Example Application
    src="scripts/require-jquery.js">


    My Example Application



    View full-size slide

  33. require(["jquery", "Car"], function($, Car) {
    var myCar = new Car('BMW', '335is Convertible', 2013);
    $("#output").html(myCar.toString());
    });
    scripts/main.js

    View full-size slide

  34. scripts/Car.js
    define(function () {
    var Constructor;
    Constructor = function(make, model, year) {
    this.make = make;
    this.model = model;
    this.year = year;
    };
    Constructor.prototype.toString = function() {
    return this.year + " " + this.make + " " +
    this.model;
    }
    return Constructor;
    });

    View full-size slide

  35. “MV*” Frameworks
    Backbone.js, KnockoutJS, AngularJS

    View full-size slide

  36. structure with models, collections, and views
    simple binding and handling of events
    connection to RESTful JSON API

    View full-size slide

  37. View Presenter
    Model
    Backbone.Model Backbone.Collection
    Templates Underscore.js Backbone.View Backbone.Router
    Backbone.Events
    Backbone.Sync

    View full-size slide

  38. Backbone.Router
    Binds URLs and hashes to routes.

    View full-size slide

  39. Backbone.Router
    MyRouter = Backbone.Router.extend({
    routes: {
    "": "index",
    "cars": "cars",
    "cars/:id": "car"
    },
    index: function() { /* show homepage */ },
    cars: function() { /* list of cars */ },
    car: function(id) { /* show car */ }
    });

    View full-size slide

  40. Backbone.View
    View takes data and transform it into HTML via
    templates and a reference to a DOM element.
    The view also listens to events and triggers action based
    those events.

    View full-size slide

  41. Backbone.View
    var CarView = Backbone.View.extend({
    tagName: "li",
    className: "car",
    events: {
    'click .start': 'start'
    },
    render: function() {
    this.$el.html(
    this.name() + ' [start]'
    );
    return this;
    },
    start: function() {
    alert('car started');
    },
    name: function() {
    return this.model.toString();
    }
    });

    View full-size slide

  42. Backbone.Model
    The model syncs with a server. If the backend is
    RESTful the “out of the box” sync will just work.
    A model holds information about a single record
    from the backend.
    Model update triggers and event which will update
    the view for that specific model.

    View full-size slide

  43. Backbone.Model
    var Car = Backbone.Model.extend({
    urlRoot: '/cars',
    toString: function() {
    return this.get('year') + " " +
    this.get('make') + " " +
    this.get('model');
    }
    });
    var CarView = Backbone.View.extend({
    initialize: function() {
    this.model.on('change', this.render, this);
    }
    /* ...snip... */
    });

    View full-size slide

  44. Backbone.Collection
    An “array” of models.
    Can also sync to the server if given a url root.

    View full-size slide

  45. Backbone.Collection
    var Cars = Backbone.Collection.extend({
    url: '/cars',
    model: Car
    });
    var CarsView = Backbone.View.extend({
    initialize: function() {
    this.collection = new Cars();
    this.collection.fetch({
    success: _.bind(function(resp, status, xhr) {
    this.render();
    }, this)
    });
    },
    render: function() {
    this.collection.each(this.renderCar, this);
    },
    renderCar: function(model) {
    var carView = new CarView({model: model});
    this.$el.append(carView.el);
    }
    });

    View full-size slide

  46. Templates in Backbone
    There is no default. You can use Underscore.js
    templates since it is a dependency.
    You are able to use whatever JavaScript templating
    such as Handlebars.

    View full-size slide

  47. QUnit
    You do test your code, don’t you?

    View full-size slide




  48. Example Test Runner


    data-main="tests.js">





    View full-size slide

  49. (function() {
    QUnit.config.autostart = false;
    require.config({
    baseUrl: "../src"
    });
    var testModules = [
    "model/CarTests.js"
    ];
    require(testModules, QUnit.start);
    }());

    View full-size slide

  50. define(function(require) {
    var Car = require("./Car");
    QUnit.module("model/Car", {
    setup: function() {},
    teardown: function() {}
    });
    QUnit.test("Car should not be running when first created",
    function() {
    var mycar = new Car('BMW', '335is', 2013);
    ok(!mycar.isRunning());
    }
    );
    QUnit.test("Car should be running after it is started",
    function() {
    var mycar = new Car("BMW", "335is", 2013);
    mycar.start();
    ok(mycar.isRunning());
    }
    );
    });

    View full-size slide

  51. Grunt
    Task-based build tool for JavaScript projects.

    View full-size slide

  52. module.exports = function(grunt) {
    grunt.initConfig({
    lint: {
    src: ['src/model/**/*.js'],
    tests: ['tests/model/**/*.js']
    },
    qunit: {
    files: ['tests/tests.html']
    },
    uglify: {}
    });
    grunt.registerTask('default', 'lint qunit');
    };

    View full-size slide

  53. $ grunt
    Running "lint:src" (lint) task
    Lint free.
    Running "lint:tests" (lint) task
    Lint free.
    Running "qunit:files" (qunit) task
    Testing tests.htmlOK
    >> 2 assertions passed (15ms)
    Done, without errors.

    View full-size slide

  54. Thank You!
    https://joind.in/7022
    @jcarouth | [email protected]
    http://speakerdeck.com/jcarouth

    View full-size slide