FRED™ is a light-weight, component-based / dependecy injected, lazy loading framework for PHP 7+. Designed for flexibility and security, and optimized for speed.
It's an MVC framework with a front-controller / router. It has auto-view-format-detection based on the extension of the request (e.g. .json for async calls; defaults to HTML).
All configuration is done through PHP files / arrays. No exotic file formats that have to be parsed, cached, and cleared upon changes.
Bootstrap
We set up a simple autoloader to make sure FRED™ can find all the classes he needs for creating himself (and to make sure you can also use FRED™ constants in the config file). After that FRED™'s own autoloader will take over (gets prepended before this one). We do not use the autoloader generated by Composer since it is not efficient (among others it pre-loads all files in autoload_files.php
).
ini.php
spl_autoload_register(function($class_name){ //basic autoloader
if(file_exists($filename = __DIR__ . '/../vendor/rsi/fred/src/' . str_replace('\\','/',$class_name) . '.php'))
require($filename);
});
$fred = new \Rsi\Fred(__DIR__ . '/../config/config.php');
Configuration
The configuration can be passed directly as an array, or by referencing to a PHP file that returns an array.
Besides some general settings for FRED™ himself, there are seperate settings for every component. Component setting can also include a specific class name for that component. If this is omitted, the default component with the same name in the FRED™ namespace is taken. Component settings can also be a string pointing to another PHP file returning an array. This file will then only be loaded when the component is created.
By prefixing the configuration key with an @
its value can be determined dynamic (using the vars
component).
config.php
$root = dirname(__DIR__);
$temp = $root . '/temp';
$public = $root . '/www';
//combine both PSR-4 and PSR-0 namespaces
$namespaces = require($root . '/vendor/composer/autoload_psr4.php');
$namespaces['Project\\'] = [$root . '/project'];
foreach(require($root . '/vendor/composer/autoload_namespaces.php') as $prefix => $paths){
$suffix = '/' . str_replace('\\','/',rtrim($prefix,'\\'));
foreach($paths as &$path) $path .= $suffix;
unset($path);
$namespaces[$prefix] = $paths;
}
//local configuration that you do not want to include in your repo or production environment
$local = require('local.php');
return array_replace_recursive([
'autoloadNamespaces' => $namespaces,
'autoloadClasses' => require($root . '/vendor/composer/autoload_classmap.php'),
'autoloadFiles' => require($root . '/vendor/composer/autoload_files.php'),
'cache' => [
'type' => 'filesystem',
'params' => [$temp . '/cache','.tmp']
],
//...
],$local);
Local configuration that you do not want to include in your repo or production environment.
local.php
return [
'debug' => true,
'db' => [
'connection' => [
'dsn' => 'mysql:host=localhost;dbname=fred',
'username' => 'fred',
'password' => '********'
]
],
//...
];
Front-controller
Bootstraps the framework by means of the above created php.ini
, creates the front controller (simply by requesting it from FRED™), and executes it.
The request is directly taken from the global $_GET
, $_POST
, $_COOKIE
, and $_FILES
variables (although there is a request
component to make life easy - among others fixing this stupid $_FILES
structure on multi-upload; in short: no PSR-7). The router will add parameters embedded in the route to the $_GET
(route blog/[id:\d+]/[title]
for example will add id
(numeric only) and title
).
The response is written directly to the standard output. The output format depends on the extension of the requested URL (.json will return JSON, .xml will return XML, etc; default is HTML format).
index.php
require('ini.php');
$fred->front->execute();
$fred->halt(); //shutdown nicely (write logs, etc)
Objects
All objects use the same magic getter/setter strategy as Yii does. There is a little bonus: private properties can also be published. In that case you don't have to specify a getter and/or setter, but you can simply mark the property as read, write, or both.
There are also some convenience functions, most notably the configure()
function which will take an array and apply it using the most appropriate method (public property, setter, or private property).
Coding style guide
The coding style is 100% PSR-1, and roughly PSR-2. Most notable differences are:
- Code MUST use 2 spaces for indenting, not tabs.
- Lines SHOULD be 127 characters or less.
- Opening braces for classes and methods MUST go on the same line.
- There MUST be one blank line before the closing braces of the class body.
- Control structure keywords MUST NOT have spaces after them.
- When present, there MUST be one blank line before the namespace declaration.
- For both the argument list of a function declaration, and the calling of a function there MUST NOT be a space after each comma.
- The body of each structure SHOULD NOT be enclosed by braces if it consists of only a single line.
- There always MUST be a line break after closing braces, EXCEPT for the closing brace of a class declaration.
Example
<?php
namespace Vendor\Package;
use FooInterface;
use BarClass as Bar;
use OtherVendor\OtherPackage\BazClass;
class Foo extends Bar implements FooInterface{
public function sampleFunction($a,$b = null){
if($a === $b){
foo();
bar();
}
elseif($a > $b) $this->bar($a);
else BazClass::bar($a,$b);
switch($a){
case 0: return 'OK';
case 1: $b = $a; break;
case 2:
case 3:
$b = null;
break;
}
do $b += ++$a;
while($a < 10);
do{
$b *= 2;
$b += ++$a;
}
while($a < 20);
}
final public static function bar($a){
// method body
}
}