https://slides.com/davesters/remove-magic-functional-php
+10 MR
$results = $accounts
->where("first_name = 'Bob'")
->andWhere("last_name = 'Sacameno'")
->andWhere('deleted IS NULL')
->andWhere('ref_id = 2')
->not()->andWhere('other_id = 3')
->orderByDesc('created')
->limit(10);
$results = $db->query("SELECT * FROM accounts WHERE
first_name = 'bob' AND last_name = 'Sacameno' AND
deleted IS NULL AND ref_id = 2 AND other_id <> 3
ORDER BY created DESC LIMIT 10");
$container->bind('iFooContext', '\Foo\Context');
$container->bind('iBarController', '\Controllers\BarController');
…
class Account {
public $id, $name, $email;
}
$account = Mapper::map('Account', $databaseAccount);
Mapper::createMap('Account')->forMember('name', function($a) {
return $a['first_name'] . ‘ ‘ . $a['last_name'];
});
Mapper::createMap('Account')->forMember('email', function($a) {
return strtolower($a['email']);
});
class Account {
public $id, $name, $email;
public function map($account) {
$this->id = $account->id;
$this->name = $account->first_name.' '.$account->last_name;
$this->email = strtolower($account->email);
}
}
$account->map($databaseAccount);
You are responsible for ALL the code in your project
"A style of building computer programs, that treats computation as the evaluation of mathematical functions and avoids changing-state and mutable data..."
- Wikipedia
+50 MR
First-class functions
Pure functions
Immutable Data
Plenty more...
$add = function ($a, $b) {
return $a + $b;
});
function getSomeAsyncData(‘foo’, function($data) {
// do something with async data here.
});
function add($a, $b) {
return $a + $b;
}
$sum = add(2, 3);
$sum = 5;
$numbers = [1, 2, 3, 4, 5];
for ($x = 0; $x < count($numbers); $x++) {
$numbers[$x] = $numbers[$x] + 5;
}
An immutable object is an object whose state cannot be modified after it is created.
foreach ($numbers as &$num) {
$num += 5;
}
$numbers = [1, 2, 3, 4, 5];
for ($x = 0; $x < count($numbers); $x++) {
$numbers[$x] = $numbers[$x] + 5;
}
$biggerNumbers = array_map(function($num) {
return $num + 5;
}, $numbers);
Functional Way
$biggerNumbers = array_map('add5', $numbers);
function add5($a) {
return $a + 5;
}
function add5($a) {
return add($a, 5);
}
$num = add5(7); // 12
function add5($num) {
return $num + 5;
}
function add($a, $b) {
return $a + $b;
}
require 'vendor/autoload.php';
require 'src/TodoApp.php';
require 'src/Mustache.php';
$handlers = [];
$mustache = Mustache::Render(new Mustache_Engine(), function($tpl) {
return file_get_contents(__DIR__ . "/views/$tpl.mustache");
});
$klein = new \Klein\Klein();
$todoApp = new TodoApp($klein, $mustache, $handlers);
$todoApp->setRoutes();
$todoApp->start();
class TodoApp {
private $app, $handlers, $mustache;
public function __construct(Klein $app, $mustache, $handlers) {
$this->app = $app;
$this->handlers = $handlers;
$this->mustache = $mustache;
}
public function start() {
$this->app->dispatch();
}
public function setRoutes() { ... }
private function handle($view, $handlers) { ... }
}
public function setRoutes() {
$h = $this->handlers;
$this->app->respond('/', $this->handle('index', $h['index']));
}
private function handle($view, array $handlers) {
// Loop over $handlers array and build view model
$this->render($this->mustache($view, $model));
}
class IndexHandler {
public static function Handle($dataSource) {
return function($model, $params) {
$todos = $dataSource('SELECT id, todo, completed
FROM todos WHERE deleted IS NULL ORDER BY created');
return [
'title' => 'Todo App',
'todos' => $todos,
'count' => count($todos)
];
};
}
}
$handlers = [
'index' => [ Handlers\IndexHandler::Handle($dataSource) ]
];
$handlers = [
'index' => [ Handlers\IndexHandler::Handle($dataSource) ],
'add' => [ Handlers\AddTodoHandler::Handle($dataSource) ],
'update' => [ Handlers\UpdateTodoHandler::Handle($dataSource) ]
];
class IndexQuery {
public static function Query($dataSource) {
return function($model, $params) {
$todos = $dataSource('SELECT id, todo, completed
FROM todos WHERE deleted IS NULL ORDER BY created');
return [ 'todos' => $todos ];
};
}
}
class IndexHandler {
public static function Handle() {
return function($model, $params) {
return [
'title' => 'Todo App',
'todos' => $model['todos']
'count' => count($model['todos']
];
};
}
}
$handlers = [
'index' => [
Queries\IndexQuery::Query($dataSource),
Handlers\IndexHandler::Handle()
],
...
];
Can I change my problem around so I don’t need it?
Sample App:
https://github.com/davesters/functional-todo-example
"8 Lines of Code" Keynote:
http://www.infoq.com/presentations/8-lines-code-refactoring
Contact:
Twitter - @davesters
Github - davesters
Website - http://www.lovesmesomecode.com