Git Product home page Git Product logo

generatedhydrator's Introduction

Generated Hydrator

GeneratedHydrator is a library about high performance transition of data from arrays to objects and from objects to arrays.

Tests Releases Downloads Dependencies
Build Status Code Coverage Scrutinizer Quality Score Latest Stable Version Latest Unstable Version Total Downloads Dependency Status

What does this thing do?

A hydrator is an object capable of extracting data from other objects, or filling them with data.

A hydrator performs following operations:

  • Convert Object to array
  • Put data from an array into an Object

GeneratedHydrator uses proxying to instantiate very fast hydrators, since this will allow access to protected properties of the object to be handled by the hydrator.

Also, a hydrator of GeneratedHydrator implements Zend\Hydrator\HydratorInterface.

Usage

Here's an example of how you can create and use a hydrator created by GeneratedHydrator:

<?php

use GeneratedHydrator\Configuration;

require_once __DIR__ . '/vendor/autoload.php';

class Example
{
    public    $foo = 1;
    protected $bar = 2;
    protected $baz = 3;
}

$config        = new Configuration('Example');
$hydratorClass = $config->createFactory()->getHydratorClass();
$hydrator      = new $hydratorClass();
$object        = new Example();

var_dump($hydrator->extract($object)); // ['foo' => 1, 'bar' => 2, 'baz' => 3]
$hydrator->hydrate(
    ['foo' => 4, 'bar' => 5, 'baz' => 6],
    $object
);
var_dump($hydrator->extract($object)); // ['foo' => 4, 'bar' => 5, 'baz' => 6]

Performance comparison

A hydrator generated by GeneratedHydrator is very, very, very fast. Here's the performance of the various hydrators of Zend\Hydrator compared to a hydrator built by GeneratedHydrator:

<?php
require_once __DIR__ . '/vendor/autoload.php';

$iterations = 10000;

class Example
{
    public $foo;
    public $bar;
    public $baz;
    public function setFoo($foo) { $this->foo = $foo; }
    public function setBar($bar) { $this->bar = $bar; }
    public function setBaz($baz) { $this->baz = $baz; }
    public function getFoo() { return $this->foo; }
    public function getBar() { return $this->bar; }
    public function getBaz() { return $this->baz; }
    public function exchangeArray($data) {
        $this->foo = $data['foo']; $this->bar = $data['bar']; $this->baz = $data['baz'];
    }
    public function getArrayCopy() {
        return array('foo' => $this->foo, 'bar' => $this->bar, 'baz' => $this->baz);
    }
}

$object        = new Example();
$data          = array('foo' => 1, 'bar' => 2, 'baz' => 3);
$config        = new GeneratedHydrator\Configuration('Example');
$hydratorClass = $config->createFactory()->getHydratorClass();
$hydrators     = array(
    new $hydratorClass(),
    new Zend\Hydrator\ClassMethods(),
    new Zend\Hydrator\Reflection(),
    new Zend\Hydrator\ArraySerializable(),
);

foreach ($hydrators as $hydrator) {
    $start = microtime(true);

    for ($i = 0; $i < $iterations; $i += 1) {
        $hydrator->hydrate($data, $object);
        $hydrator->extract($object);
    }

    var_dump(microtime(true) - $start);
}

This will produce something like following:

0.028156042098999s
2.606673002243s
0.56710886955261s
0.60278487205505s

As you can see, the generated hydrator is 20 times faster than Zend\Hydrator\Reflection and Zend\Hydrator\ArraySerializable, and more than 90 times faster than Zend\Hydrator\ClassMethods.

Tuning for Production

By default, GeneratedHydrator will generate hydrators on every new request. While this is relatively fast, it will cause I/O operations, and you can achieve even better performance by pre-generating your hydrators and telling your application to autoload them instead of generating new ones at each run.

Avoiding regeneration involves:

  1. pre-generating your hydrators
  2. ensuring that your autoloader is aware of them

The instructions that follow assume you are using Composer.

Pre-generating your hydrators

There is no built-in way to bulk-generate all required hydrators, so you will need to do so on your own.

Here is a simple snippet you can use to accomplish this:

require '/path/to/vendor/autoload.php'; // composer autoloader

// classes for which we want to pre-generate the hydrators
$classes = [
    \My\Namespace\ClassOne::class,
    \My\Namespace\ClassTwo::class,
    \My\Namespace\ClassThree::class,
];

foreach ($classes as $class) {
    $config = new \GeneratedHydrator\Configuration($class);

    $config->setGeneratedClassesTargetDir('/path/to/target-dir');
    $config->createFactory()->getHydratorClass();
}

Just add all the classes for which you need hydrators to the $classes array, and have your deployment process run this script. When complete, all of the hydrators you need will be available in /path/to/target-dir.

Making the autoloader aware of your hydrators

Using your pre-generated hydrators is as simple as adding the generation target directory to your composer.json:

{
    "autoload": {
        "classmap": [
            "/path/to/target-dir"
        ]
    }
}

After generating your hydrators, have your deployment script run composer dump-autoload to regenerate your autoloader. From now on, GeneratedHydrator will skip code generation and I/O if a generated class already exists.

Fallback autoloader

Alternatively, GeneratedHydrator comes with a built-in autoloader that you can register on your own. This simplifies deployment, but is a bit slower:

$config = new \GeneratedHydrator\Configuration(\My\Namespace\ClassOne::class);

spl_autoload_register($config->getGeneratedClassAutoloader());

// now simply use your hydrator, and if possible, code generation will be skipped:
$hydratorName = $config->createFactory()->getHydratorClass();
$hydrator     = new $hydratorName();

Contributing

Please read the CONTRIBUTING.md contents if you wish to help out!

generatedhydrator's People

Contributors

ocramius avatar pounard avatar gsdevme avatar haampie avatar staabm avatar samsonasik avatar ostrolucky avatar krymen avatar leedavis81 avatar magnusnordlander avatar thadafinser avatar michaelmoussa avatar remicollet avatar siwinski avatar sasezaki avatar prolic avatar

Watchers

James Cloos avatar Alessandro Feitoza avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.