PHPackages                             tobento/app - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. tobento/app

ActiveLibrary

tobento/app
===========

Base application for creating any PHP project.

2.0.2(4mo ago)02934MITPHPPHP &gt;=8.4

Since Feb 12Pushed 4mo ago1 watchersCompare

[ Source](https://github.com/tobento-ch/app)[ Packagist](https://packagist.org/packages/tobento/app)[ Docs](https://www.tobento.ch)[ RSS](/packages/tobento-app/feed)WikiDiscussions 2.x Synced today

READMEChangelog (10)Dependencies (15)Versions (14)Used By (4)

App
===

[](#app)

Base application for creating any PHP project.
You might get started with the [**App Skeleton**](https://github.com/tobento-ch/app-skeleton) where you will find a list of available app bundles.

Table of Contents
-----------------

[](#table-of-contents)

- [Getting Started](#getting-started)
    - [Requirements](#requirements)
- [Documentation](#documentation)
    - [App Lifecycle](#app-lifecycle)
    - [App Factory](#app-factory)
    - [App Resolving](#app-resolving)
        - [PSR-11](#psr-11)
        - [Autowiring](#autowiring)
        - [Definitions](#definitions)
        - [Make](#make)
        - [Call](#call)
        - [On](#on)
    - [App Booting](#app-booting)
    - [App Directories](#app-directories)
    - [App Clock](#app-clock)
    - [App Macros](#app-macros)
    - [Available Boots](#available-boots)
        - [App Boot](#app-boot)
        - [Config Boot](#config-boot)
        - [Functions Boot](#functions-boot)
        - [Error Handling Boot](#error-handling-boot)
        - [Dater Boot](#dater-boot)
    - [Handle Boot Errors](#handle-boot-errors)
    - [Customization](#customization)
- [Credits](#credits)

---

Getting Started
===============

[](#getting-started)

Add the latest version of the app project running this command.

```
composer require tobento/app

```

Requirements
------------

[](#requirements)

- PHP 8.4 or greater

Documentation
=============

[](#documentation)

App Lifecycle
-------------

[](#app-lifecycle)

First, create the app from the provided app factory.
Next, register any boot you want within your app.
Finally, run your app.

```
use Tobento\App\AppFactory;

// Create the app
$app = new AppFactory()->createApp();

// Adding boots
$app->boot(\Tobento\App\Boot\App::class);
$app->boot(\Tobento\App\Boot\ErrorHandling::class);

// Run the app
$app->run();
```

App Factory
-----------

[](#app-factory)

```
use Tobento\App\AppFactory;
use Tobento\App\AppFactoryInterface;
use Tobento\App\AppInterface;
use Tobento\Service\Resolver\ResolverFactoryInterface;
use Tobento\Service\Booting\BooterInterface;
use Tobento\Service\Dir\DirsInterface;

$appFactory = new AppFactory();

var_dump($appFactory instanceof AppFactoryInterface);
// bool(true)

$app = $appFactory->createApp(
    id: 'root', // default
    resolverFactory: null, // null|ResolverFactoryInterface
    booter: null, // null|BooterInterface
    dirs: null, // null|DirsInterface
);

var_dump($app instanceof AppInterface);
// bool(true)
```

**Parameters explanation**

ParameterDescription**id**A unique app id.**resolverFactory**If no resolver factory is set, it uses the [Resolver Container](https://github.com/tobento-ch/service-resolver-container).**booter**If no booter is set, it uses the [Default Booter](https://github.com/tobento-ch/service-booting#booter).**dirs**If no dirs is set, it uses the [Default Dirs](https://github.com/tobento-ch/service-dir#create-dirs).App Resolving
-------------

[](#app-resolving)

### PSR-11

[](#psr-11)

```
use Tobento\App\AppFactory;

class Foo {}

$app = new AppFactory()->createApp();

var_dump($app->has(Bar::class));
// bool(false)

var_dump($app->get(Foo::class));
// object(Foo)#2 (0) { }
```

### Autowiring

[](#autowiring)

The app resolves any dependencies by autowiring, except build-in parameters needs a [definition](#definitions) to be resolved.

On union types parameter, the first resolvable parameter gets used if not set by definiton.

### Definitions

[](#definitions)

```
use Tobento\App\AppFactory;
use Tobento\Service\Resolver\DefinitionInterface;

class Foo
{
    public function __construct(
        protected string $name
    ) {}
}

$app = new AppFactory()->createApp();

$definition = $app->set(Foo::class)->construct('name');

var_dump($definition instanceof DefinitionInterface);
// bool(true)
```

Check out the [**Resolver Definitions**](https://github.com/tobento-ch/service-resolver#definitions) to learn more about definitions in general.

### Make

[](#make)

```
use Tobento\App\AppFactory;

class Foo
{
    public function __construct(
        private Bar $bar,
        private string $name
    ) {}
}

class Bar {}

$app = new AppFactory()->createApp();

$foo = $app->make(Foo::class, ['name' => 'value']);
```

Check out [**Resolver Make**](https://github.com/tobento-ch/service-resolver#make) to learn more about it.

### Call

[](#call)

```
use Tobento\App\AppFactory;

class Foo
{
    public function index(Bar $bar, string $name): string
    {
        return $name;
    }
}

class Bar {}

$app = new AppFactory()->createApp();

$name = $app->call([Foo::class, 'index'], ['name' => 'value']);

var_dump($name);
// string(5) "value"
```

Check out [**Resolver Call**](https://github.com/tobento-ch/service-resolver#call) to learn more about it.

### On

[](#on)

```
use Tobento\App\AppFactory;

class AdminUser {}
class GuestUser {}

$app = new AppFactory()->createApp();

$app->on(AdminUser::class, GuestUser::class);

$user = $app->get(AdminUser::class);

var_dump($user);
// object(GuestUser)#16 (0) { }
```

Check out [**Resolver On**](https://github.com/tobento-ch/service-resolver#on) to learn more about it.

App Booting
-----------

[](#app-booting)

You may call the **booting** method to boot the registered boots so as having access to its functionality, otherwise it gets called on the **run** method.

```
use Tobento\App\AppFactory;
use Tobento\App\Boot;

interface ServiceInterface {}
class Service implements ServiceInterface {}

class ServiceBoot extends Boot
{
    public function boot()
    {
        $this->app->set(ServiceInterface::class, Service::class);
    }
}

$app = new AppFactory()->createApp();

$app->boot(ServiceBoot::class);

var_dump($app->has(ServiceInterface::class));
// bool(false)

// Do the booting.
$app->booting();

var_dump($app->has(ServiceInterface::class));
// bool(true)

// Run the app
$app->run();
```

App Directories
---------------

[](#app-directories)

You may add directories for its later usage.

```
use Tobento\App\AppFactory;
use Tobento\Service\Dir\DirsInterface;

$app = new AppFactory()->createApp();

$app->dirs()
    ->dir(dir: 'path/to/config', name: 'config', group: 'config')
    ->dir(dir: 'path/to/view', name: 'view');

var_dump($app->dir(name: 'view'));
// string(13) "path/to/view/"

var_dump($app->dirs() instanceof DirsInterface);
// bool(true)
```

Check out the [**Dir Service**](https://github.com/tobento-ch/service-dir) to learn more about dirs in general.

App Clock
---------

[](#app-clock)

```
use Tobento\App\AppFactory;
use Psr\Clock\ClockInterface;

$app = new AppFactory()->createApp();

// Get the app clock:
var_dump($app->clock() instanceof ClockInterface);
// bool(true)

// or:
var_dump($app->get(ClockInterface::class) instanceof ClockInterface);
// bool(true)
```

App Macros
----------

[](#app-macros)

```
use Tobento\App\AppFactory;

$app = new AppFactory()->createApp();

$app->addMacro('lowercase', function(string $string): string {
    return strtolower($string);
});

var_dump($app->lowercase('Lorem'));
// string(5) "lorem"
```

Check out the [**Macro Service**](https://github.com/tobento-ch/service-macro) to learn more about macros in general.

Available Boots
---------------

[](#available-boots)

### App Boot

[](#app-boot)

The app boot does the following:

- boots [Config Boot](#config-boot) and [Functions Boot](#functions-boot)
- loads app config file if exist
- sets app environment based on app config
- adds specific config directory for environment
- sets timezone based on app config
- boots the specified boots from app config

```
use Tobento\App\AppFactory;

$app = new AppFactory()->createApp();

$app->boot(\Tobento\App\Boot\App::class);

$app->run();
```

### Config Boot

[](#config-boot)

The config boot does the following:

- implements the config interface
- adds config macro

Check out the [**Config Service**](https://github.com/tobento-ch/service-config/#documentation) to learn more about it in general.

```
use Tobento\App\AppFactory;
use Tobento\Service\Config\ConfigInterface;

$app = new AppFactory()->createApp();

$app->dirs()->dir(
    dir: 'path/to/config',
    name: 'config',
    group: 'config'
);

$app->boot(\Tobento\App\Boot\Config::class);

$app->booting();

// using interface
$value = $app->get(ConfigInterface::class)->get(
    key: 'app.key',
    default: 'default',
    locale: 'de'
);

// using macro:
$value = $app->config('app.key', 'default');

var_dump($value);
// string(7) "default"

$app->run();
```

### Functions Boot

[](#functions-boot)

The functions boot does the following:

- registers app functions
- provides register method
- adds app functions macro

Check out the [**Helper Function Service**](https://github.com/tobento-ch/service-helper-function) to learn more about it in general.

```
use Tobento\App\AppFactory;
use Tobento\App\AppInterface;

use function Tobento\App\{app, directory, config};

$app = new AppFactory()->createApp();

$app->boot(\Tobento\App\Boot\Functions::class);
$app->booting();

// App function:
var_dump(app() instanceof AppInterface);
// bool(true)

// Directory function:
$app->dirs()->dir('dir/to/foo', 'foo');

var_dump(directory('foo'));
// string(11) "dir/to/foo/"

// Config function:
$app->boot(\Tobento\App\Boot\Config::class);
$app->booting();

var_dump(config(key: 'foo', default: 'foo'));
// string(3) "foo"

// using functions macro:
// $app->functions(__DIR__.'/my-functions.php');

// using boot method:
// $app->get(\Tobento\App\Boot\Functions::class)->register(__DIR__.'/my-functions.php');

$app->run();
```

### Error Handling Boot

[](#error-handling-boot)

The error handling boot does the following:

- implements the error handling

```
use Tobento\App\AppFactory;

$app = new AppFactory()->createApp();

$app->boot(\Tobento\App\Boot\ErrorHandling::class);

$app->run();
```

### Dater Boot

[](#dater-boot)

The dater boot does the following:

- configures DateFormatter with the app.timezone and app.locale config

Check out the [**Dater Service**](https://github.com/tobento-ch/service-dater#documentation) to learn more about in general.

```
use Tobento\App\AppFactory;
use Tobento\Service\Dater\DateFormatter;

$app = new AppFactory()->createApp();

$app->boot(\Tobento\App\Boot\Dater::class);

$app->booting();

$df = $app->get(DateFormatter::class);

var_dump($df->date('now'));
// string(25) "Freitag, 11. Februar 2022"

$app->run();
```

Handle Boot Errors
------------------

[](#handle-boot-errors)

You might want to handle errors caused by boots in order to continue running the app:

```
use Tobento\App\AppFactory;
use Tobento\App\Boot;
use Tobento\App\BootErrorHandlersInterface;
use Tobento\App\BootErrorHandlers;
use Tobento\Service\ErrorHandler\AutowiringThrowableHandlerFactory;

class CausesErrorBoot extends Boot
{
    public function boot(): void
    {
        echo $test();
    }
}

$app = new AppFactory()->createApp();

$app->set(BootErrorHandlersInterface::class, function() use ($app) {

    $handlers = new BootErrorHandlers(
        new AutowiringThrowableHandlerFactory($app->container())
    );

    $handlers->add(function(Throwable $t): mixed {
        return null;
    });

    return $handlers;
});

$app->boot(\Tobento\App\Boot\ErrorHandling::class);

$app->boot(CausesErrorBoot::class);

$app->run();
```

Check out the [**Throwable Handlers**](https://github.com/tobento-ch/service-error-handler#throwable-handlers) to learn more about handlers in general.

Customization
-------------

[](#customization)

Some boots might implement interfaces on their boot method such as the [**app http boot**](https://github.com/tobento-ch/app-http#http-boot). There are several ways to change its implementations. But we need to keep in mind that other boots might have [**dependent boots**](https://github.com/tobento-ch/service-booting#dependent-boot) defined.

**Using the app on method**

```
use Tobento\App\Boot;
use Tobento\App\Http\Boot\Http;
use Psr\Http\Message\ResponseFactoryInterface;

class CustomBoot extends Boot
{
    public function boot(): void
    {
        $this->app->on(
            ResponseFactoryInterface::class,
            \Laminas\Diactoros\ResponseFactory::class
        );
    }
}

$app = new AppFactory()->createApp();

$app->boot(CustomBoot::class);

$app->run();
```

**Boot extending**

```
use Tobento\App\Boot;
use Tobento\App\Http\Boot\Http;
use Tobento\App\Migration\Boot\Migration;
use Psr\Http\Message\ResponseFactoryInterface;

class CustomHttpBoot extends Http
{
    /**
     * Boot application services.
     *
     * @param Migration $migration
     * @return void
     */
    public function boot(Migration $migration): void
    {
        parent::boot($migration);

        // set your custom implementations.
        $this->app->set(
            ResponseFactoryInterface::class,
            \Laminas\Diactoros\ResponseFactory::class
        );
    }
}

$app = new AppFactory()->createApp();

$app->on(Http::class, CustomHttpBoot::class);

$app->run();
```

**Boot implementation overwriting**

```
use Tobento\App\Boot;
use Tobento\App\Http\Boot\Http;
use Psr\Http\Message\ResponseFactoryInterface;

class CustomBoot extends Boot
{
    public const BOOT = [
        Http::class,
    ];

    public function boot(Http $http): void
    {
        // set your custom implementations.
        $this->app->set(
            ResponseFactoryInterface::class,
            \Laminas\Diactoros\ResponseFactory::class
        );
    }
}

$app = new AppFactory()->createApp();

$app->boot(CustomBoot::class);

$app->run();
```

Credits
=======

[](#credits)

- [Tobias Strub](https://www.tobento.ch)
- [All Contributors](../../contributors)

###  Health Score

48

—

FairBetter than 95% of packages

Maintenance77

Regular maintenance activity

Popularity15

Limited adoption so far

Community13

Small or concentrated contributor base

Maturity73

Established project with proven stability

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~105 days

Recently: every ~37 days

Total

14

Last Release

127d ago

Major Versions

1.x-dev → 2.02025-10-01

PHP version history (2 changes)1.0.0PHP &gt;=8.0

2.0PHP &gt;=8.4

### Community

Maintainers

![](https://www.gravatar.com/avatar/055d6a1b5c2384bb179c75ab0b55914231d898fdc4dffeb30770f81200e52206?d=identicon)[TOBENTOch](/maintainers/TOBENTOch)

---

Top Contributors

[![tobento-ch](https://avatars.githubusercontent.com/u/16684832?v=4)](https://github.com/tobento-ch "tobento-ch (36 commits)")

---

Tags

phppackageapplicationtobento

###  Code Quality

TestsPHPUnit

Static AnalysisPsalm

Type Coverage Yes

### Embed Badge

![Health badge](/badges/tobento-app/health.svg)

```
[![Health](https://phpackages.com/badges/tobento-app/health.svg)](https://phpackages.com/packages/tobento-app)
```

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
