FRED logo

FRED™

PHP Framework for Rapid and Easy Development

FRED™ is a light-weight, component-based / dependecy injected, lazy loading framework for PHP 5.5+ (bullshit bingo anyone?). 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:

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
  }

}