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");