Skip to content

Instantly share code, notes, and snippets.

@juzna
Created September 15, 2011 09:46
Show Gist options
  • Save juzna/1218914 to your computer and use it in GitHub Desktop.
Save juzna/1218914 to your computer and use it in GitHub Desktop.
Renderers
<?php
class Movie {
const GENRE_HORROR = 1;
const GENRE_SCIFI = 2;
const GENRE_FAMILY = 3;
const GENRE_X0 = 4; // just to have more labels (for performance testing)
const GENRE_X1 = 5;
const GENRE_X2 = 6;
const GENRE_X3 = 7;
const GENRE_X4 = 8;
const GENRE_X5 = 9;
const GENRE_X6 = 10;
const GENRE_X7 = 11;
const GENRE_X8 = 12;
const GENRE_X9 = 13;
public $genre;
public $name;
/**
* @param string $name
* @param int $genre
*/
function __construct($name, $genre) {
$this->name = $name;
$this->genre = $genre;
}
}
interface IRenderer {
/** @return string[] Classes which I can render */
function getRenderables();
/** @param mixed $object @return string */
function render($object);
}
interface ILabelRenderer extends IRenderer {
function renderByIndex($x);
function getIndexByLabel($label);
}
<?php
/**
* Ancestor for all renderers, makes sure that we render only what's possible to be rendered
*/
abstract class AbstractRenderer implements IRenderer {
// actual renderer implementation
abstract protected function _render($obj);
final public function render($object)
{
$className = get_class($object);
if(!in_array($className, $this->getRenderables())) throw new Exception("Unable to render '$className'");
return $this->_render($object);
}
}
/**
* Ancestor for all renderers, which convert numeric property into human readable label
*/
abstract class LabelRenderer extends AbstractRenderer implements ILabelRenderer {
/** @return string[int] All labels based on integral index */
abstract protected function getLabels();
/** @return string Property of object to be rendered */
abstract protected function getPropertyName();
final protected function _render($obj) {
// AbstractRenderer makes sure that object is one of getRenderables
$x = $obj->{$this->getPropertyName()};
return $this->renderByIndex($x);
}
final public function renderByIndex($x) {
$tmp = $this->getLabels();
if (isset($tmp[$x])) return $tmp[$x];
else return null;
}
final public function getIndexByLabel($label) {
return array_search($label, $this->getLabels());
}
}
<?php
/**
* Ancestor for all renderers, makes sure that we render only what's possible to be rendered
*/
abstract class AbstractRenderer implements IRenderer {
protected $renderables;
final public function getRenderables() {
// just to support the interface
return $this->renderables;
}
// actual renderer implementation
abstract protected function _render($obj);
final public function render($object)
{
$className = get_class($object);
if(!in_array($className, $this->renderables)) throw new Exception("Unable to render '$className'");
return $this->_render($object);
}
}
/**
* Ancestor for all renderers, which convert numeric property into human readable label
*/
abstract class LabelRenderer extends AbstractRenderer implements ILabelRenderer {
/** @return string[int] All labels based on integral index */
protected $labels;
/** @return string Property of object to be rendered */
protected $propertyName;
final protected function _render($obj) {
// AbstractRenderer makes sure that object is one of getRenderables
$x = $obj->{$this->propertyName};
return $this->renderByIndex($x);
}
final public function renderByIndex($x) {
if (isset($this->labels[$x])) return $this->labels[$x];
else return null;
}
final public function getIndexByLabel($label) {
return array_search($label, $this->labels);
}
}
<?php
class MovieNameRenderer extends AbstractRenderer {
function getRenderables() {
return array('Movie');
}
function _render($obj) {
return $obj->name;
}
}
class MovieGenreRender extends LabelRenderer {
function getRenderables() {
return array('Movie');
}
protected function getPropertyName() {
return 'genre';
}
protected function getLabels() {
return array(
Movie::GENRE_HORROR => 'Horror',
Movie::GENRE_SCIFI => 'Sci-Fi',
Movie::GENRE_FAMILY => 'Family',
Movie::GENRE_X0 => 'Dummy 0',
Movie::GENRE_X1 => 'Dummy 1',
Movie::GENRE_X2 => 'Dummy 2',
Movie::GENRE_X3 => 'Dummy 3',
Movie::GENRE_X4 => 'Dummy 4',
Movie::GENRE_X5 => 'Dummy 5',
Movie::GENRE_X6 => 'Dummy 6',
Movie::GENRE_X7 => 'Dummy 7',
Movie::GENRE_X8 => 'Dummy 8',
Movie::GENRE_X9 => 'Dummy 9',
);
}
}
<?php
class MovieNameRenderer extends AbstractRenderer {
protected $renderables = array('Movie');
function _render($obj) {
return $obj->name;
}
}
class MovieGenreRender extends LabelRenderer {
protected $renderables = array('Movie');
protected $propertyName = 'genre';
protected $labels = array(
Movie::GENRE_HORROR => 'Horror',
Movie::GENRE_SCIFI => 'Sci-Fi',
Movie::GENRE_FAMILY => 'Family',
Movie::GENRE_X0 => 'Dummy 0',
Movie::GENRE_X1 => 'Dummy 1',
Movie::GENRE_X2 => 'Dummy 2',
Movie::GENRE_X3 => 'Dummy 3',
Movie::GENRE_X4 => 'Dummy 4',
Movie::GENRE_X5 => 'Dummy 5',
Movie::GENRE_X6 => 'Dummy 6',
Movie::GENRE_X7 => 'Dummy 7',
Movie::GENRE_X8 => 'Dummy 8',
Movie::GENRE_X9 => 'Dummy 9',
);
}
<?php
$which = @$argv[1];
if(!$which) die("Usage: php test.php methods|properties\n");
require __DIR__ . '/basic.php';
require __DIR__ . "/$which/basic.php";
require __DIR__ . "/$which/definitions.php";
function showList($list, IRenderer $col1, ILabelRenderer $col2) {
$counter = 0;
foreach($list as $item) {
// render and throw away
$txt = sprintf("%d: %s (%s)\n", ++$counter, $col1->render($item), $col2->render($item));
// try to test labelToIndex
$dummy = $col2->getIndexByLabel($col2->render($item));
if($dummy !== $item->genre) throw new Exception("Assert failed");
}
}
// Test
$start = microtime(true);
// Initialize test
{
$movies = array();
for ($i = 0; $i < 1e6; $i++) $movies[] = new Movie("Movie $i", rand(1, 13));
showList($movies, new MovieNameRenderer, new MovieGenreRender);
}
$end = microtime(true);
printf("Using $which - duration: %f\n", $end - $start);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment