0xDEADBEEF

RSS odkazy english edition

phplisp.php

3. 5. 2012 #kód

Object oriented system made only from functions

<?php

// If you want to make an object oriented system from scratch, you must first create the universe.
// Only things you need are functions

function cons($h, $t) {
  return function($what) use($h, $t) {
    return ($what[0] === 'h') ? $h : $t;
  };
}

$__nilFunction = function() { return null; };
function nil() {
  global $__nilFunction;
  return $__nilFunction;
}

function makeList() {
  return array_reduce(array_reverse(func_get_args()), function ($res, $arg) { return cons($arg, $res); }, nil());
}

function head($l) { return $l === nil() ? null  : $l('head'); }
function tail($l) { return $l === nil() ? nil() : $l('tail'); }
function find($l, $f) {
  if ($l === nil()) return null;
  else {
    $h = head($l);
    $t = tail($l);
    if ($f($h)) return $h;
    else        return find($t, $f);
  }
}

function concat($prefix, $suffix) {
  if ($suffix === nil())       return $prefix;
  else if ($prefix === nil())  return $suffix;
  else {
    $x = function ($l) use(&$x, $suffix) {
        if ($l !== nil()) {
          $h = head($l);
          $t = tail($l);
          return cons($h, $x($t));
        } else {
          return $suffix;
        }
    };
    return $x($prefix);
  }
}


function deleg($childMethods, $parentMethods) {
  return concat($childMethods, $parentMethods);
}

function call($object, $method) {
  $m = find($object, function ($x) use($method) { return head($x) === $method; });
  $m = tail($m);
  return $m($object);
}

// you can call methods on prettyfied objects by passing arguments to this object
// $obj('method') insted od call($obj, 'method')
function prettify($methods) { return function ($method) use($methods) { return call($methods, $method); }; }

function property($val) { return function () use($val) { return $val; }; }


// objects are nothing more than collections of methods
$parent = makeList(
  cons("x", function ($self) { return 'parent.x'; }),
  cons("y", function ($self) { return 'parent.y -> ' . call($self, 'x'); })
);

$childMethods = makeList(
  cons("x", function ($self) { return 'child.x'; })
);

$child = deleg($childMethods, $parent);


var_dump(call($parent, 'x') === 'parent.x');
var_dump(call($parent, 'y') === 'parent.y -> parent.x');

var_dump(call($child,  'x') === 'child.x');
var_dump(call($child,  'y') === 'parent.y -> child.x'); // look, virtual call and open recursion


$makePerson = function ($name, $mail) {
  return makeList(
    cons('name', property($name)),
    cons('mail', property($mail)),
    cons('contact', function ($self) { return 'name: ' . call($self, 'name') . ' mail: ' . call($self, 'mail'); })
  );
};

$person = $makePerson('kaja47', 'bumfluff@k47.cz');
$person2 = deleg(makeList(cons('name', property('Anonymous'))), $person);

var_dump(call($person, 'contact')  === "name: kaja47 mail: bumfluff@k47.cz");
var_dump(call($person2, 'contact') === "name: Anonymous mail: bunfluff@k47.cz");

$pp = prettify($person);
var_dump($pp('contact') === "name: kaja47 mail: bumfluff@k47.cz");
píše k47 (@kaja47, k47)