PHPackages                             justim/vice - 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. [Framework](/categories/framework)
4. /
5. justim/vice

ActiveLibrary[Framework](/categories/framework)

justim/vice
===========

Vice is a small web framework for easy dispatching actions for a given URL

3152PHP

Since Mar 11Pushed 11y ago1 watchersCompare

[ Source](https://github.com/justim/vice)[ Packagist](https://packagist.org/packages/justim/vice)[ RSS](/packages/justim-vice/feed)WikiDiscussions master Synced 6d ago

READMEChangelogDependenciesVersions (1)Used By (0)

Vice
====

[](#vice)

Vice is a small web framework for easy dispatching actions for a given URL.

It uses some nifty tricks to make sure you don't have to;

- Easy restriction of HTTP-methods
- Simple AJAX response
- Arguments filled based on their name, for easy access
- Named parameters in the URI
- Powerfull filters

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

[](#requirements)

- PHP &gt;= 5.4

Installation
------------

[](#installation)

- For Vice to work you only need the `Vice.php` file, download it and hack away
- Also available at [Packagist](https://packagist.org/packages/justim/vice) (Composer)

Example application
-------------------

[](#example-application)

You can check the `example`-directory in this repository to see it all in action. You can run the example with PHPs builtin server:

```
php -S localhost:9000 -t example/

```

Now open  in your browser to see the example.

Examples
--------

[](#examples)

### Basic example

[](#basic-example)

```
$app = new Vice;
$app->route('/', function()
{
    echo 'Hello world!';
});
$app->run();
```

### JSON Helper

[](#json-helper)

```
$app = new Vice;

// route that only responds to ajax-post requests
$app->post('/users', 'is:ajax', function($json)
{
    // builtin helper, sets a header, encodes it, and dies
    $json([
        [
            'name' => 'Pizza kat',
        ]
    ]);
});
```

### Global store

[](#global-store)

```
$app = new Vice('/', [
    'db' => new Database, // some database connection
]);

$app->get('/', function($db)
{
    // $db is the one that you put in the store
});
```

### Advanced filters

[](#advanced-filters)

```
$app = new Vice;
$app->registerFilter('is:logged', function()
{
    if (/* some login check */)
    {
        return [
            'name' => 'Flavored mushrooms',
        ];
    }
    else
    {
        return false;
    }
});

$app->get('/admin', 'is:logged', function($isLogged)
{
    // $isLogged would contain the result of the filter,
	// if the filter fails, then this function is never called
	echo 'Hello ' . $isLogged['name'] . '!';
});
```

*Note: filters are run everytime they are called.*

### Subapps

[](#subapps)

```
$app = new Vice('/', [ 'db' => new Database ]);
$users = new Vice;

$users->get('', function($json, $db, $id, $param)
{
    // $param('id') === $id
    $json($db->users->get($id));
});

// users subapp is available at /users and only for ajax-get-requests
// this would make the route /users/1 available
$app->get('users', 'is:ajax', $users);
```

*Subapps share the filters and store from their parent, but not the other way around.*

### Multiple filters chained

[](#multiple-filters-chained)

```
$app = new Vice('/', [ 'currentUser' => 1, 'db' => new Database ]);

$app->registerFilter('is:logged', function($db, $currentUser)
{
    // check for existince of current user and return it
    return $db->users->get($currentUser) ?: false;
});

$app->registerFilter('is:admin', function($isLogged)
{
    return $isLogged['admin'] === true;
});

$app->route('admin', 'is:logged is:admin', function($isLogged)
{
    echo 'Hello ' . $isLogged['name'] . ', you are an admin!';
});

// a different way to handle this is by making a filter dependable
// on another filter. this way you don't have to specify 'is:logged'
// in your route definition
$app->registerFilter('is:admin', 'is:logged', function($isLogged)
{
	return $isLogged['admin'] === true;
});

$app->route('admin', 'is:admin', function($isLogged)
{
	// $isLogged is still available, even though it was not specified for this particular route
    echo 'Hello ' . $isLogged['name'] . ', you are an admin!';
});
```

Builtin filters
---------------

[](#builtin-filters)

- GET-request
- POST-request
- PUT-request
- DELETE-request
- AJAX-request

*(by `$app->get(..)` or as a filter `$app->route('/', 'is:get')` (same for all others)*

Builtin named arguments
-----------------------

[](#builtin-named-arguments)

- `$post` -&gt; `function($key, $default = null)`-wrapper for `$_POST`
- `$get` -&gt; `function($key, $default = null)`-wrapper for `$_GET`
- `$param` -&gt; `function($key, $default = null)`-wrapper for the parameters in the URI
- `$server` -&gt; `function($key, $default = null)`-wrapper for `$_SERVER`
- `$store` -&gt; `function($key, $default = null)`-wrapper for the global store
- `$filter` -&gt; `function($key, $default = null)`-wrapper for passed filter results
- `$ajax` -&gt; `boolean` that tells you if the request is an AJAX one
- `$json` -&gt; `function($data)` JSON helper
- Keys from the `params`, `store`, `filterResults` (in that order)

Some technical insights
-----------------------

[](#some-technical-insights)

- Every route is compiled to a regex, which is then matched against the current URI. When a match is found all the defined filters for that route are tested. If it is still a match, then we run the corresponding action. When the action is an app itself, the whole process is ran again, but without the prefix we already matched. After some looping something probably happened and we're done.
- `Reflection` is used to determine the value of the arguments
- It's a single class, everything else is a function

TODO
----

[](#todo)

- Some proper error handling

###  Health Score

22

—

LowBetter than 22% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity11

Limited adoption so far

Community9

Small or concentrated contributor base

Maturity41

Maturing project, gaining track record

 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.

### Community

Maintainers

![](https://www.gravatar.com/avatar/5addc442589060d2c83836f11b851560df560ac2da1156b20ba0e93788467c7a?d=identicon)[justim](/maintainers/justim)

---

Top Contributors

[![justim](https://avatars.githubusercontent.com/u/757292?v=4)](https://github.com/justim "justim (11 commits)")

### Embed Badge

![Health badge](/badges/justim-vice/health.svg)

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

###  Alternatives

[laravel/telescope

An elegant debug assistant for the Laravel framework.

5.2k67.8M192](/packages/laravel-telescope)[spiral/roadrunner

RoadRunner: High-performance PHP application server and process manager written in Go and powered with plugins

8.4k12.2M84](/packages/spiral-roadrunner)[nolimits4web/swiper

Most modern mobile touch slider and framework with hardware accelerated transitions

41.8k177.2k1](/packages/nolimits4web-swiper)[laravel/dusk

Laravel Dusk provides simple end-to-end testing and browser automation.

1.9k36.7M259](/packages/laravel-dusk)[laravel/prompts

Add beautiful and user-friendly forms to your command-line applications.

708181.8M596](/packages/laravel-prompts)[cakephp/chronos

A simple API extension for DateTime.

1.4k47.7M121](/packages/cakephp-chronos)

PHPackages © 2026

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