Yaf: a PHP MVC framework compiled as a C extension
Ultra-fast PHP MVC framework built as a C extension
At a glance
- What is it?
- Yaf moves the framework itself out of PHP and into a C extension, so bootstrap, routing and dispatch run in compiled code. It suits high-traffic and long-lived PHP services, and it is a poor fit for teams that expect Composer, PSR-4 and a large ecosystem of PHP packages.
- Who is it for?
- Adopt Yaf when framework bootstrap overhead is a measured cost in your request path, or when you run long-lived workers with Swoole, RoadRunner or ReactPHP and want a dispatcher that holds no per-request PHP state. Do not adopt it if your application depends on Composer autoloading, PSR interfaces or a large set of PHP packages, because Yaf replaces the autoloader rather than cooperating with it by default.
- Can I use it commercially?
- Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
- Is it still maintained?
- Yes. The repository last received commits 7 days ago.
- What is it written in?
- Mainly C, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 30, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What Yaf actually removes from the request path
A conventional PHP framework is a pile of PHP files. On every request, the autoloader walks the filesystem, includes class files, and builds the class table before your controller runs. Yaf deletes that step. The README states that Yaf is "not 'yet another PHP framework' - it's a C framework exposed through PHP", and that every class, router match and dispatch cycle runs in compiled C rather than interpreted PHP. The practical consequence is stated plainly: there are no PHP files to require for the framework itself, and new Yaf_Application() is instant because the router and dispatcher are already loaded in the extension's shared memory.
The intended audience is narrow and specific. The README names two scenarios: high-traffic applications where framework bootstrap overhead dominates, and long-lived services such as Swoole, RoadRunner and ReactPHP where you do not want the framework to be the bottleneck. It also claims each request gets a clean dispatch cycle with no static caches to leak, which is the property that matters when a worker process serves thousands of requests without restarting. If your application is a low-traffic internal tool, none of this buys you anything, and you pay for it in flexibility.
The dispatch pipeline and how configuration reaches it
The repository layout shows the architecture directly. Separate C source files exist for the application, bootstrap, dispatcher, controller, action, loader, plugin, config and registry, each with a matching .stub.php file and generated arginfo headers. Those stub files are how modern PHP extensions declare their API to the engine, and their presence here confirms that the classes are implemented in C, not in PHP.
Entry is always through public/index.php. It constructs a Yaf_Application with the path to conf/application.ini, calls bootstrap(), then run(). The bootstrap class extends Yaf_Bootstrap_Abstract, and the README states that any method whose name starts with _init is called automatically in definition order, each receiving the Yaf_Dispatcher instance. That gives you a deterministic startup sequence for config, plugins and routes without a service container.
Configuration arrives through application.ini, and the INI setting yaf.environ selects which section is loaded, defaulting to "product". Routing and class resolution are governed by a set of INI switches: yaf.name_suffix chooses between IndexController and Controller_Index naming, yaf.name_separator replaces the underscore between module and class name in multi-module setups, yaf.use_namespace switches to Yaf\Application style names, and yaf.action_prefer moves actions into standalone classes under an actions/ directory. The loader handles class loading, and yaf.use_spl_autoload decides whether Yaf registers itself on the SPL autoload stack instead of replacing __autoload. That last switch is the one that determines whether Yaf can coexist with another autoloader, and its default of 0 means it cannot without a change.
Installing Yaf and running a first request
Yaf is a PECL extension, so the shortest install path is PECL itself. The README gives this command.
pecl install yafSince 3.3.8 there is a second option, PIE, the PHP Installer for Extensions. The README shows this form.
pie install laruence/yafIf you need to build against a specific PHP, the README documents phpize, configure with --with-php-config, then make and make install. After installation the extension must be enabled in php.ini before any of the classes exist.
The application layout is fixed enough that the README prints it: a public directory holding index.php, css, js and img; a conf directory holding application.ini; and an application directory holding Bootstrap.php, controllers, views, library, models and plugins. DocumentRoot is set to application/public so that only the public folder is reachable over HTTP, and all requests are rewritten to index.php. The entry file is small, and the README gives it in full.
<?php
define("APPLICATION_PATH", dirname(dirname(__FILE__)));
$app = new Yaf_Application(APPLICATION_PATH . "/conf/application.ini");
$app->bootstrap()
->run();A minimal Bootstrap.php extends Yaf_Bootstrap_Abstract and defines one or more _init methods. The README's example uses _initConfig, _initPlugin and _initRoute, and notes they are called in definition order. For IDE completion, tools/ide/ ships yaf_classes.php and yaf_classes_namespace.php, generated by reflecting over the real extension, and the README documents the regeneration command using php -d extension=yaf.so tools/ide/yaf.php. If you load the extension and construct Yaf_Application against a valid application.ini, the router resolves the request to a controller and action; the README does not state what a missing controller returns, so treat that as something to confirm in your own environment.
Where Yaf stops being the right tool
The autoloader behaviour is the sharpest edge. yaf.use_spl_autoload defaults to 0, which means Yaf replaces __autoload rather than joining the SPL stack. Projects that lean on Composer for their own classes need that switch set to 1, and even then the two loaders are sharing one namespace space, so collisions in class naming are a real possibility rather than a theoretical one.
The second limitation is the absence of the ecosystem that makes PHP frameworks productive. There is no documented middleware pipeline, no service container, no PSR-7 request object and no Composer-installed framework package to upgrade. You build those layers yourself or do without. A team that chose its framework because of its package ecosystem will find Yaf actively hostile to that choice, because the framework is not a library you can partially adopt. It is an extension that takes over dispatch.
The third is operational. Installing a C extension means the deployment artifact is a compiled .so or .dll matched to a PHP version and build, not a directory of PHP files. The README documents the build steps and the AppVeyor, Linux and Windows CI badges, but it does not document a rollback procedure for a failed extension upgrade, so downgrade planning is on you. The README also does not describe error handling when application.ini is missing or malformed.
Yaf against a Composer-based framework
The honest comparison is with a mainstream Composer framework such as Laravel or Symfony. The difference is not features, it is where the framework lives. A Composer framework is PHP code that your application includes and can patch, subclass or replace at any layer; its overhead comes from loading and interpreting that code on every request. Yaf is compiled into the PHP process, so the overhead is a fixed cost paid once at startup, and the framework code is not something you can edit.
That inversion explains almost every other trade-off. You gain a dispatcher that is already resident and, per the README, holds no static caches to leak between requests. You lose the ability to read the framework source as PHP, to override a method by subclassing at the framework level, and to install a package that extends the framework. The README also points to two companion extensions by the same author, Yaconf for static configuration and Yac for runtime caching, describing all three as sharing a "local first, zero dependency, C-native" design. That is a coherent stack, but it is a stack you assemble, not one you install.
Maintenance, licensing and upgrade cost
The last push to the repository was on 2026-09-13, and the most recent release listed is 3.3.8 from 2026-08-18. The repository is not archived. The master branch requires PHP 7.0+, and a php5 branch exists for PHP 5.2+. The presence of generated arginfo headers and .stub.php files for each class means the API surface is declared to the engine, so PHP version bumps tend to require regenerating those files rather than rewriting class bodies; that is a smaller maintenance burden than it sounds, but it is still a rebuild and redeploy of a binary artifact per PHP version.
The licence is reported as NOASSERTION, which means the repository's licence metadata does not resolve to a standard SPDX identifier. The LICENSE file is present at the top level, so the terms exist, but anyone embedding Yaf in a product should read that file directly rather than infer terms from the metadata. Nothing here is legal advice.
Upgrade cost is the interesting part. Because Yaf is an extension, version skew between the extension and the PHP runtime is a deployment failure, not a runtime warning. Pin the extension version alongside the PHP version in your image, and regenerate the IDE stubs with the documented command when the API changes.
Editorial conclusion
Adopt Yaf when framework bootstrap overhead is a measured cost in your request path, or when you run long-lived workers with Swoole, RoadRunner or ReactPHP and want a dispatcher that holds no per-request PHP state. Do not adopt it if your application depends on Composer autoloading, PSR interfaces or a large set of PHP packages, because Yaf replaces the autoloader rather than cooperating with it by default. Before committing, verify that your PHP version satisfies the master branch requirement of PHP 7.0+, decide whether you need yaf.use_namespace or yaf.name_suffix conventions, and confirm how application.ini is loaded per environment, since the README documents the layout and the INI keys but does not document a rollback path for a failed extension upgrade.
Frequently asked questions
What does the acronym YAF stand for in the laruence/yaf project?
The README expands it as "Yet Another Framework", and the repository is titled "Yaf - Yet Another Framework".
How do I install the Yaf PHP extension?
The README gives two package-manager routes, pecl install yaf and, since 3.3.8, pie install laruence/yaf, plus a source build using phpize, configure with --with-php-config, make and make install.
Which PHP versions does Yaf support?
The master branch requires PHP 7.0 or later, and the README points to a separate php5 branch for PHP 5.2 and above.
Does Yaf work with Composer autoloading?
Only if you change the default. The yaf.use_spl_autoload setting defaults to 0, which means Yaf replaces __autoload rather than registering on the SPL autoload stack; setting it to 1 is described in the README as useful when coexisting with other autoloaders.
How does Yaf decide which environment configuration to load?
The yaf.environ INI setting selects the section loaded from application.ini and defaults to "product".
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/laruence-yaf)