Yaf - Yet Another Framework

August 3, 2026 · View on GitHub

Build status Build Status

Yaf is a PHP framework with high performance. It is written in C and built as a PHP extension.

When to use Yaf

Yaf is not "yet another PHP framework" — it's a C framework exposed through PHP. Every class, every router match, every dispatch cycle runs in compiled C code rather than interpreted PHP. The result: constant overhead per request measured in microseconds, not milliseconds.

This matters most in two scenarios:

  • High-traffic applications where framework bootstrap overhead becomes the dominant cost. Yaf eliminates the class-file loading cascade of Composer-based frameworks — there are no PHP files to require for the framework itself. new Yaf_Application() is instant; the router and dispatcher are already loaded in the extension's shared memory.
  • Long-lived services (Swoole, RoadRunner, ReactPHP) where you want your framework to not be the bottleneck. Yaf has no global state pollution issues across requests — each request gets a clean dispatch cycle with no static caches to leak.

Yaf pairs naturally with the rest of the "Yet Another" ecosystem:

  • Use Yaconf for static configuration — it eliminates the INI parse overhead that Yaf_Config_Ini pays on every request.
  • Use Yac for runtime caching — database results, computed data, HTML fragments. All three share the same "local first, zero dependency, C-native" design philosophy.

Requirement

Install

Install via PECL

Yaf is a PECL extension, which means you can simply install it by:

$ pecl install yaf

Compile from source

$ /path/to/phpize
$ ./configure --with-php-config=/path/to/php-config
$ make && make install

Runtime Configuration

INI SettingDefaultDescription
yaf.environ"product"Default environment name. This maps to the INI section loaded from application.ini
yaf.library""Global library directory, searched after the application's local library
yaf.forward_limit5Maximum number of forward() calls allowed in a single request. Prevents infinite loops
yaf.name_suffix1When 1, classes use suffix naming (IndexController). When 0, uses prefix naming (Controller_Index)
yaf.name_separator""In multi-module setups, replaces the underscore between module and class name. E.g. with "/": Admin/IndexController instead of Admin_IndexController
yaf.use_namespace0When 1, enables namespaced class names (Yaf\Application, Yaf\Controller_Abstract, etc.)
yaf.action_prefer0When 1, actions are resolved as standalone Yaf_Action_Abstract classes in an actions/ subdirectory instead of controller methods
yaf.lowcase_path0When 1, all paths are lowercased before class loading (e.g. controllers/Index.phpcontrollers/index.php)
yaf.use_spl_autoload0When 1, Yaf registers itself on the SPL autoload stack instead of replacing __autoload. Useful when coexisting with other autoloaders

Documentation

Yaf manual can be found at: http://www.php.net/manual/en/book.yaf.php

For IDE

A documented prototype script can be found at: https://github.com/elad-yosifon/php-yaf-doc

Tutorial

Application Directory Layout

A classic single-module application directory layout is:

- .htaccess  # Rewrite rules
+ public
  | - index.php  # Application entry
  | + css
  | + js
  | + img
+ conf
  | - application.ini  # Configuration
- application/
  - Bootstrap.php  # Bootstrap
  + controllers
     - Index.php  # Default controller
  + views
     |+ index
        - index.phtml  # View template for default controller
  + library  # Libraries
  + models   # Models
  + plugins  # Plugins

For multi-module applications, the layout is:

+ public/
+ conf/
+ application/
  + modules/
    + Index/       # Default module
      + controllers/
      + views/
    + Admin/       # Another module
      + controllers/
      + views/
  + library/
  + models/
  + plugins/
  - Bootstrap.php

DocumentRoot

Set DocumentRoot to application/public, so only the public folder is accessible from the web.

index.php

index.php in the public directory is the only way into the application. You should rewrite all requests to it (using .htaccess in Apache + mod_php, or the equivalent in your web server).

<?php
define("APPLICATION_PATH", dirname(dirname(__FILE__)));

$app = new Yaf_Application(APPLICATION_PATH . "/conf/application.ini");
$app->bootstrap() // call bootstrap methods defined in Bootstrap.php
    ->run();

Bootstrap

A minimal Bootstrap.php looks like this:

<?php
class Bootstrap extends Yaf_Bootstrap_Abstract
{
    public function _initConfig(Yaf_Dispatcher $dispatcher)
    {
        // put your init logic here
    }
}

Bootstrap auto-calling: Any method in Bootstrap whose name starts with _init is automatically called in definition order by Yaf_Application::bootstrap(). Each method receives the Yaf_Dispatcher instance as its first argument.

<?php
class Bootstrap extends Yaf_Bootstrap_Abstract
{
    public function _initConfig(Yaf_Dispatcher $dispatcher)
    {
        // called first
    }

    public function _initPlugin(Yaf_Dispatcher $dispatcher)
    {
        // called second
    }

    public function _initRoute(Yaf_Dispatcher $dispatcher)
    {
        // called third
    }

    // This is NOT auto-called — doesn't start with _init
    public function helperMethod()
    {
    }
}

Rewrite Rules

Apache

#.htaccess
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule .* index.php

Nginx

server {
    listen      80;
    server_name domain.com;
    root        /path/to/document/root;
    index       index.php index.html index.htm;

    location / {
        try_files $uri $uri/ /index.php?$args;
    }
}

Lighttpd

$HTTP["host"] =~ "(www.)?domain.com$" {
    url.rewrite = (
        "^/(.+)/?$" => "/index.php/\$1",
    )
}

application.ini

application.ini is the application config file:

[product]
; Constants defined in index.php are supported
application.directory = APPLICATION_PATH "/application/"

Alternatively, you can use a PHP array instead:

<?php
$config = [
    "application" => [
        "directory" => APPLICATION_PATH . "/application/",
    ],
];

$app = new Yaf_Application($config);

Default Controller

In Yaf, the default controller is named IndexController:

<?php
class IndexController extends Yaf_Controller_Abstract
{
    // default action name
    public function indexAction()
    {
        $this->getView()->content = "Hello World";
    }
}

View Script

The view script for the default controller and default action is application/views/index/index.phtml. Yaf provides a simple view engine called Yaf_View_Simple, which supports view templates written in PHP:

<html>
  <head>
    <title>Hello World</title>
  </head>
  <body>
    <?php echo $content; ?>
  </body>
</html>

Run the Application

Point your browser to your configured domain (e.g. http://www.example.com) and you should see "Hello World".

Code Generator

You can generate the example above using Yaf Code Generator:

$ ./yaf_cg -d output_directory [-a application_name] [--namespace]

The code generator is located at: https://github.com/laruence/yaf/tree/master/tools/cg

Core Concepts

Routing

Yaf supports 6 built-in route types, all implementing Yaf_Route_Interface:

RouteDescription
Yaf_Route_StaticDefault route — /module/controller/action
Yaf_Route_SimpleMaps query-string parameters to module/controller/action
Yaf_Route_SupervarUses a single GET/POST variable for routing path (e.g. ?r=/module/controller/action)
Yaf_Route_RewritePattern-matching rewrite with named capture groups
Yaf_Route_RegexFull regex matching with capture-to-variable mapping
Yaf_Route_MapMaps the first URI segment to either controller or action

Routes can be registered in Bootstrap:

<?php
class Bootstrap extends Yaf_Bootstrap_Abstract
{
    public function _initRoute(Yaf_Dispatcher $dispatcher)
    {
        $router = $dispatcher->getRouter();

        // Pattern: /user/123 → controller=user, action=index, id=123
        $router->addRoute("user", new Yaf_Route_Rewrite(
            "/user/:id",
            ["controller" => "user", "action" => "index"]
        ));

        // Regex:  /item/123.html → controller=item, action=view, id=123
        $router->addRoute("item", new Yaf_Route_Regex(
            "#^/item/(\d+)\.html$#",
            ["controller" => "item", "action" => "view"],
            [1 => "id"]
        ));
    }
}

Routes can also be loaded from INI config:

$router->addConfig(new Yaf_Config_Ini("routes.ini"));

Configuration

Yaf provides two configuration parsers:

Yaf_Config_Ini

Parses standard INI files. Supports section inheritance:

[common]
db.host = "localhost"
db.port = 3306

[product : common]
db.user = "app_user"
db.pass = "secret"

The [product : common] syntax inherits all keys from [common] then applies its own overrides.

Yaf_Config_Simple

Parses PHP arrays or INI files into a mutable configuration object. Values can be modified at runtime:

<?php
$config = new Yaf_Config_Simple([
    "db" => ["host" => "localhost"],
]);
$config->db->host = "10.0.0.1"; // editable

In contrast, Yaf_Config_Ini is always read-only.

Performance tip: If you have a large amount of static configuration, consider using Yaconf — a persistent configuration container that keeps configs in shared memory across the entire PHP lifecycle, providing significantly faster access than parsing INI files on every request.

Plugins

Yaf supports a plugin hook system via Yaf_Plugin_Abstract. Override any of 7 hooks:

<?php
class UserPlugin extends Yaf_Plugin_Abstract
{
    public function routerStartup(Yaf_Request_Abstract $request, Yaf_Response_Abstract $response) {}
    public function routerShutdown(Yaf_Request_Abstract $request, Yaf_Response_Abstract $response) {}
    public function dispatchLoopStartup(Yaf_Request_Abstract $request, Yaf_Response_Abstract $response) {}
    public function preDispatch(Yaf_Request_Abstract $request, Yaf_Response_Abstract $response) {}
    public function postDispatch(Yaf_Request_Abstract $request, Yaf_Response_Abstract $response) {}
    public function dispatchLoopShutdown(Yaf_Request_Abstract $request, Yaf_Response_Abstract $response) {}
    public function preResponse(Yaf_Request_Abstract $request, Yaf_Response_Abstract $response) {}
}

Register in Bootstrap:

$dispatcher->registerPlugin(new UserPlugin());

Exceptions

Yaf defines a structured exception hierarchy:

Exception
└── Yaf_Exception
    ├── Yaf_Exception_StartupError     — Application startup failure
    ├── Yaf_Exception_RouterError      — Route matching failure
    ├── Yaf_Exception_DispatchError    — Dispatch failure
    ├── Yaf_Exception_LoadFailed       — Class/Method/View load failure
    └── Yaf_Exception_TypeError         — Type mismatch

You can control whether Yaf throws or silently swallows exceptions during dispatch:

$dispatcher->throwException(true);  // throw to user
$dispatcher->catchException(true);  // catch and store in request

Core Classes Quick Reference

ClassPurpose
Yaf_ApplicationApplication bootstrap and lifecycle
Yaf_DispatcherRequest dispatch pipeline
Yaf_Controller_AbstractBase controller — use forward(), redirect(), render(), display()
Yaf_Action_AbstractStandalone action class (requires yaf.action_prefer = 1)
Yaf_Bootstrap_AbstractAuto-called _init* methods
Yaf_LoaderPSR-0 style class autoloading
Yaf_RouterRoute registration and matching
Yaf_RegistryStatic key-value store (get/set/has/del)
Yaf_SessionNamespaced session wrapper with ArrayAccess
Yaf_Config_IniRead-only INI config parser
Yaf_Config_SimpleMutable config from INI or PHP array
Yaf_Request_HttpHTTP request abstraction
Yaf_Request_SimpleSynthetic request (CLI / testing)
Yaf_Response_HttpHTTP response with header management
Yaf_Response_CliCLI response
Yaf_View_SimplePHP-template view engine (assign, render, display, eval, assignRef, clear)
Yaf_Plugin_Abstract7-hook plugin base class

Yaf_Registry

Yaf_Registry is a static key-value store — a global data bus accessible from anywhere in the application. All methods are static.

Yaf_Registry::set("user_config", $config);
$config = Yaf_Registry::get("user_config");
Yaf_Registry::has("user_config");  // true
Yaf_Registry::del("user_config");  // removes the key

Common use: storing objects initialized in Bootstrap (e.g. a database connection, a logger instance) so controllers can access them without re-initializing.

Yaf_Session

Yaf_Session is a namespaced wrapper around PHP's native $_SESSION. It implements ArrayAccess, Iterator, and Countable, and supports property-style access.

$session = Yaf_Session::getInstance();
$session->start();

// All equivalent:
$session->set("user", $data);
$session["user"] = $data;
$session->user = $data;

$session->get("user");
$session["user"];
$session->user;

$session->has("user");
isset($session->user);

$session->del("user");
unset($session["user"]);
unset($session->user);

$session->clear();  // removes all keys
count($session);    // number of keys

More

More info can be found at the Yaf Manual: http://www.php.net/manual/en/book.yaf.php

License

PHP-3.01