Skip to content

Commit bb37bc7

Browse files
committed
Updated mu to be only 3 lines long
1 parent 5dd72cc commit bb37bc7

File tree

11 files changed

+160
-74
lines changed

11 files changed

+160
-74
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ vendor
22
composer.phar
33
composer.lock
44
.DS_Store
5+
*.log

README.md

Lines changed: 41 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
# The µ PHP Microframework
22

3-
[![Code Climate](https://codeclimate.com/github/jeremeamia/mu/badges/gpa.svg)](https://codeclimate.com/github/jeremeamia/mu)
4-
5-
A _"real"_ microframework that fits in **just 4 lines of code**.
3+
A _"real"_ microframework that fits in **just 3 lines of code**.
64

75
The "microframeworks" out there weren't _micro_ enough for me, so I brushed up on
86
some of my code golfing skills to create **µ**.
@@ -11,34 +9,34 @@ some of my code golfing skills to create **µ**.
119

1210
## Features
1311

14-
These 4 LOC come jam-packed with features!
12+
These 3 LOC come jam-packed with features!
1513

1614
### Easy, regex-based routing system
1715

1816
Follows the well-established route-to-callable microframework pattern.
1917

2018
```php
21-
echo (new µ)
22-
->get('/hello', function ($app) {
23-
return "<p>Hello, world!</p>";
19+
(new µ)
20+
->get('/hello', function () {
21+
echo "<p>Hello, world!</p>";
2422
})
2523
->run();
2624
```
2725

2826
Allows you to access parameters from the URL.
2927

3028
```php
31-
echo (new µ)
29+
(new µ)
3230
->get('/hello/(?<name>\w+)', function ($app, $params) {
33-
return "<p>Hello, {$params['name']}!</p>";
31+
echo "<p>Hello, {$params['name']}!</p>";
3432
})
3533
->run();
3634
```
3735

3836
Supports all your favorite HTTP verbs.
3937

4038
```php
41-
echo (new µ)
39+
(new µ)
4240
->delete('/user/(?<id>\d+)', $fn)
4341
->get('/user/(?<id>\d+)', $fn)
4442
->head('/user/(?<id>\d+)', $fn)
@@ -48,38 +46,32 @@ echo (new µ)
4846
->run();
4947
```
5048

51-
Supports wildcard verbs too, because sometimes you are just making a web page
52-
and you really don't care about esoteric HTTP practices.
49+
### Simple dependency/config container
5350

5451
```php
55-
echo (new µ)
56-
->any('/', $fn)
57-
->run();
58-
```
59-
60-
### Simple, but powerful, dependency injection container
61-
62-
```php
63-
use Monolog\Logger;
6452
use Monolog\Handler\StreamHandler;
53+
use Monolog\Logger;
6554

66-
echo (new µ)
55+
(new µ)
6756
->cfg('log.channel', 'your-app')
68-
->cfg('log.handler', function ($app) {
69-
return new StreamHandler('path/to/your.log', Logger::WARNING);
57+
->cfg('log.handler', function () {
58+
return new StreamHandler('path/to/your.log', Logger::DEBUG);
7059
})
7160
->cfg('log', function ($app) {
7261
$log = new Logger($app->cfg('log.channel'));
7362
$log->pushHandler($app->cfg('log.handler'));
7463
return $log;
7564
})
7665
->get('/hello/(?<name>\w+)', function ($app, $params) {
77-
$app->cfg('log')->addDebug("Said hello to {$params['name']}.");
78-
return "<p>Hello, {$params['name']}!</p>";
66+
$app->cfg('log')->debug("Said hello to {$params['name']}");
67+
echo "<p>Hello, {$params['name']}!</p>";
7968
})
8069
->run();
8170
```
8271

72+
If a callable is provided (like with `log.handler` above), then it is treated as a factory and is only called once to
73+
produce a singleton value for efficient, multiple accesses.
74+
8375
### A truly _elegant_ and fluent interface
8476

8577
_See previous example (I'm lazy)._
@@ -102,40 +94,50 @@ Templates are just PHP files—no mustaches and no frills.
10294

10395
```php
10496
// index.php
105-
echo (new µ)
97+
(new µ)
10698
->cfg('views', __DIR__ . '/templates')
107-
->any('/hello/(?<name>\w+)', function ($app, $params) {
108-
return $app->view('hello', [
99+
->get('/hello/(?<name>\w+)', function ($app, $params) {
100+
echo $app->view('hello', [
109101
'greeting' => 'howdy',
110102
'name' => $params['name'],
111103
]);
112104
})
113105
->run();
114106
```
115107

116-
No twigs, plates, or blades to cut you or poke you.
108+
No Twigs, Plates, or Blades to cut you or poke you. That might feel a little _dull_, but it's simple.
117109

118110
## Design constraints
119111

120112
* Must have at least a Router, Container, and Templating System as features.
121113
* Must attempt to incorporate usage patterns (e.g., chainable methods, closures
122114
as controllers) that resemble other contemporary microframeworks.
123115
* Must work with `error_reporting` set to `-1` (all errors reported).
124-
* Must not exceed 4 lines of code (LOC), where each line is <= 120 characters.
116+
* Must not exceed 3 lines of code (LOC), where each line is <= 120 characters.
125117
* Must not have dependencies on other packages.
126-
* May break traditional coding conventions for the sake of brevity.
127-
* Must be hand-written.
118+
* May break traditional coding conventions/styles for the sake of brevity.
119+
* Must be hand-written, not minified/obfuscated by any tools.
128120

129121
## It works, but it's really just a joke.
130122

131123
Don't use this in production, or really anywhere. It's just for fun. :smile:
132124

133-
If you want to use a production-quality _microframework_, try one of these:
125+
If you want to use a production-quality _microframework_, try [Slim](http://www.slimframework.com/).
134126

135-
* [Slim](http://www.slimframework.com/)
136-
* [Lumen](http://lumen.laravel.com/)
137-
* Zend [Diactoros](https://docs.zendframework.com/zend-diactoros/) or [Expressive](https://docs.zendframework.com/zend-expressive/)
127+
## Examples
138128

139-
## Is there a PHP 7 Version?
129+
The code examples in this README are also shipped as working examples in the `/examples` directory.
140130

141-
Not yet. Waiting for 7.4 with shorthand closures before I attempt anything.
131+
To run an example, use the built-in PHP server.
132+
```bash
133+
# For the hello1 example:
134+
php -S localhost:8000 examples/hello1.php
135+
```
136+
Then access `http://localhost:8000` in your browser or via cURL.
137+
138+
## Tests
139+
140+
A very basic test suite is included, and can be run via:
141+
```bash
142+
php test.php
143+
```

composer.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,11 @@
66
"type": "project",
77
"autoload": {
88
"files": ["mu.php"]
9+
},
10+
"dependencies": {
11+
"php": ">=7.0"
12+
},
13+
"require-dev": {
14+
"monolog/monolog": "^2.2"
915
}
10-
}
16+
}

examples/hello1.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
require __DIR__ . '/../vendor/autoload.php';
6+
7+
(new µ)
8+
->get('/hello', function () {
9+
echo "<p>Hello, world!</p>";
10+
})
11+
->run();

examples/hello2.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
require __DIR__ . '/../vendor/autoload.php';
6+
7+
(new µ)
8+
->get('/hello/(?<name>\w+)', function ($app, $params) {
9+
echo "<p>Hello, {$params['name']}!</p>";
10+
})
11+
->run();

examples/hello3.php

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
use Monolog\Handler\StreamHandler;
6+
use Monolog\Logger;
7+
8+
require __DIR__ . '/../vendor/autoload.php';
9+
10+
(new µ)
11+
->cfg('log.channel', 'hello3')
12+
->cfg('log.handler', function () {
13+
return new StreamHandler(__DIR__ . '/hello3.log', Logger::DEBUG);
14+
})
15+
->cfg('log', function ($app) {
16+
$log = new Logger($app->cfg('log.channel'));
17+
$log->pushHandler($app->cfg('log.handler'));
18+
return $log;
19+
})
20+
->get('/hello/(?<name>\w+)', function ($app, $params) {
21+
$app->cfg('log')->debug("Said hello to {$params['name']}");
22+
echo "<p>Hello, {$params['name']}!</p>";
23+
})
24+
->run();

examples/hello4.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
require __DIR__ . '/../vendor/autoload.php';
6+
7+
(new µ)
8+
->cfg('views', __DIR__ . '/templates')
9+
->get('/hello/(?<name>\w+)', function ($app, $params) {
10+
echo $app->view('hello4', [
11+
'greeting' => 'howdy',
12+
'name' => $params['name'],
13+
]);
14+
})
15+
->run();

examples/templates/hello4.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<html>
2+
<head>
3+
<title>World Greeter</title>
4+
</head>
5+
<body>
6+
<p><?= ucfirst($greeting) ?>, <?= $name ?>!</p>
7+
</body>
8+
</html>

examples/verbs.php

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
require __DIR__ . '/../vendor/autoload.php';
6+
7+
$fn = function () {
8+
header('X-Test: Hello!', true, 200);
9+
if ($_SERVER['REQUEST_METHOD'] !== 'HEAD') {
10+
echo <<<HTML
11+
<ul>
12+
<li>Method: {$_SERVER['REQUEST_METHOD']}</li>
13+
<li>URI: {$_SERVER['REQUEST_URI']}</li>
14+
</ul>
15+
HTML;
16+
}
17+
};
18+
19+
(new µ)
20+
->delete('/user/(?<id>\d+)', $fn)
21+
->get('/user/(?<id>\d+)', $fn)
22+
->head('/user/(?<id>\d+)', $fn)
23+
->patch('/user/(?<id>\d+)', $fn)
24+
->post('/users', $fn)
25+
->put('/user/(?<id>\d+)', $fn)
26+
->run();

mu.php

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
<?php class µ{function cfg($k,$v=null){$c=&$this->$k;if($v===null)return$c=is_callable($c)?$c($this):$c;$c=$v;return
2-
$this;}function __call($m,$a){$this->{($m=='any'?'':$m).$a[0]}=$a[1];return$this;}function run(){foreach($this as$x=>$f)
3-
if(preg_match("@$x@i","$_SERVER[REQUEST_METHOD]$_SERVER[REQUEST_URI]",$p))return$f($this,$p);}function view($f,$d=[]){
4-
ob_start();extract($d);require"$this->views/$f.php";return ob_get_clean();}}
1+
<?php class µ{function __call($m,$a){$c=&$this->{$m.$a[0]};$c=$a[1]??(is_callable($c)?$c($this):$c);return isset($a[1])?
2+
$this:$c;}function run(){foreach($this as$x=>$f)preg_match("@$x@i","$_SERVER[REQUEST_METHOD]$_SERVER[REQUEST_URI]",$p)&&
3+
$f($this,$p);}function view($f,$d=[]){ob_start();extract($d);require"$this->cfgviews/$f.php";return ob_get_clean();}}

0 commit comments

Comments
 (0)