Horus Framework Version 2.0

" Code is poetry, So Let's Be Smart "



What is Horus ?

An OOP PHP micro-framework, a lightweight toolkit to help developers lay down the foundation of their PHP-based websites and applications . The Horus Framework is a pretty solid attempt at designing a good OOP framework in as a small package as possible. Focused on a light codebase and on a solid, standards-friendly approach, Horus can be used to write advanced applications without having to deal with complex coding toolkits like Zend or CakePHP. Horus is easy to learn and the code is pretty well commented in case developers need help figuring out what's going on -- "Softpedia"

What is Horus Framework Features ?

  • No Complex Code
  • Built-in Smart Router
  • Built-in Events/Hooks
  • Built-in Database Class
  • Built-in Simple ORM
  • Built-in Secure Session Management
  • Built-in Full Output Control
  • Built-in Views Manager
  • Built-in Smart Autoloader
  • Built-in HTTP Manager
  • Built-in helpful functions
  • Easy Configurations
  • Extensible
  • Control Any thing in Horus Without Hacking The Core
  • No Big files on loading to start

What is new in this version ?

  • Removed events class, replaced with just 3 tiny functions
  • Removed loader class, replaced with a smart tiny auto(load&map) function
  • Updated the mod_rewrite simulator
  • New Functions
  • Removed non-helpful codes
  • Re-Optimized the core
  • New Hooks/Events in the core
  • Horus Classes Now Under your Full Control

What Requirements Horus Need ?

  • Any Web Server e.g: Apache
  • PHP 5 tested on PHP 5.2

How to download Horus ?

There are many ways to download it:

Who made Horus Framework ?

The Horus Framework Created By Mohammed Alashaal and still the core developer for it, Also there are some good contributers .
After downloading the Horus Framework Version 2.0 from the introduction, you don't need any thing to do except for uncompress it then start coding directly . Now open your index.php and start ,


    // include horus
    require_once 'Horus/Horus.php';
    
    // start it
    new Horus;
    
    // say hello world
    echo "Hello World";


Now use your your browser t open it, you will see Hello World, Easy or not :) . You can notice that we didn't use any routing , but how about saying hello world using Horus Router ?


    // include horus
    require_once 'Horus/Horus.php';
    
    // start it and tell horus to use it's own router
    new Horus( array( 
        'horus.use_router'          =>  yes //  yes = true
        'horus.enable_simulator'    =>  yes //  enable simulator if your server has no support for mod_rewrite
    ));
    
    // respond to a get request saying "Hello World"
    horus('router') -> get('/', function(){
        echo "Hello World";
    });

Now Goto Horus with your browser you will see Hello World

Horus Framework is built-in very easy configurations to control what you want .


How to config Horus ?


    // 1)- when you construct horus, just give it an assoc-array of configurations, like this
    new Horus(array('key' => 'value'));
    
    // 2)- using config() method
    horus()->config('key', 'value');
    # or
    horus()->config(array('key' => 'value'));
    
    // to fetch any configuration
    echo horus()->config('key');
    

List of available configurations

key value default
horus.use_router true / false false
horus.timezone see it on PHP.net PHP Default
horus.default_404 a callback e.g function(){ echo '404 not found'; } Horus Default
horus.auto_run true / false true
if you set it to false, you must type horus()->run(); at the end of your index.php
horus.http_version string 1.1
horus.enable_simulator true / false false
if your server has no support for mod_rewrite, set to true/yes
horus.session_name string HORUS_SESSID
horus.session_hash_function Se it on PHP.net 1
horus.session_use_only_cookies Se it on PHP.net true
horus.session_http_only Se it on PHP.net true
horus.session_regenerate_id true / false true
horus.session_save_path string PHP Default
horus.enable_gzip true / false true
horus.minify_output true / false false
horus.fix_html true / false false only if the page is html
horus.fix_xml true / false false only if the page is xml and fix_html is false
horus.mode dev / production dev

Features

  • Supports Callbacks Routing
  • Supports Class Routing
  • Supports Nested Routing
  • Supports RESTful Request Routing
  • Easy to use
  • Light & Small Code
  • Regex Based
  • Built-in Regex shortcuts
  • Clean Urls even if you have no support for mod_rewrite, just enable horus simulator
  • Respond to any HTTP Method even custom

Supported HTTP Methods

With Horus Router You can respond to GET, POST, PUT , HEAD, DELETE, .... etc .

Examples:


    // include horus core
    require_once "Horus/Horus.php";
    
    // Construct it
    // Note that my server supports mod_rewrite, so i don't need simulator
    // And i'm working on PHP 5.4, so i use the new array style [], you can use array()
    new Horus( [ 'horus.use_router' => yes ] );
    
    // i'll use horus('router')-> or horus()->router->
    
    // Respond to a get request on the '/page-1' path
    horus('router') -> get('/page-1', function(){
        echo 'We are in get request';
    });
    
    // Respond to a post request on the '/page-1' path
    horus('router') -> post('/page-1', function(){
        echo 'We are in post request';
    });

    // Respond to a put request on the '/page-1' path
    horus('router') -> put('/page-1', function(){
        echo 'We are in put request';
    });
    
    // Respond to a put, get request on the '/page-1' path
    horus('router') -> put_get('/page-1', function(){
        echo 'We are in put or get request';
    });
    
    // Respond to a put, post get request on the '/page-1' path
    horus('router') -> put_post_get('/page-1', function(){
        echo 'We are in put,post or get request';
    });
    
    // Respond to all/any requests ( get, post, put, patch, ... etc ) on the '/page-1' path
    horus('router') -> any('/page-1', function(){
        echo 'We are in any request';
    });
    
    // And so, you can use any http method
    // just "horus('router') -> {method}($pattern, $callback)"
    

Supported Callbacks


Anonymous/Lambada Function


// after you included horus and started it

// sample usage
horus('router') -> any('/', function(){
    echo 'hello';
});

// with parameters
horus('router') -> any('/{alpha}', function($arg){
    echo 'hello ', $arg;
});

horus('router') -> any('/{alpha}/{num}', function($alpha, $num){
    echo 'hello ', $alpha, ' ', $num;
});

// NOTE: anonymous function is only available in PHP >= PHP 5.3

// You can use lambada
horus('router') -> any('/', create_function('', 'echo "hello";'));

# {alpha} is a regexp shortuct, all shortucts are:
# {num}     --->    ([0-9\.]+)          { example "152423" }
# {alpha}   --->    ([a-zA-Z]+)         { example: "mystring" }
# {alnum}   --->    ([a-zA-Z0-9\.]+)    { example: "mystring132.321" }
# {str}     --->    ([a-zA-Z0-9-_\.]+)  { example: "my-string_132.345" }
# {any}     --->    '.+'                { supports any char }
# {*}       --->    '?|(.*?)'           { to apply the callback on all sub-paths }

Basic Function


// after you included horus and started it

// sample usage
function func_1()
{
    echo 'hello';
}
horus('router') -> any('/', 'func_1');

// with parameters
function func_2($name)
{
    echo "hello ", $name;
}
horus('router') -> any('/{alpha}', 'func_2');

function func_3($alpha, $num)
{
    echo 'hello ', $alpha, ' ', $num;
}
horus('router') -> any('/{alpha}/{num}', 'func_3');

Class methods


// after you included horus and started it

// Simple Class
Class Test
{
    public static function page1()
    {
        echo we are in "page1";
    }
    
    public function page2()
    {
        echo we are in "page2";
    }
    
    function insert()
    {
        // ...
    }
}

// construct it
$text = new Test;

// Route some methods from it
horus('router') -> any('/p1', 'Test::page1');
horus('router') -> any('/p2', array( $test, 'page2' ));
horus('router') -> any('/p2', [ $test, 'page2' ]); // only in PHP >= PHP 5.4

Class Routing


// after you included horus and started it

// Simple Class
Class Test2
{
    public function index()
    {
        // this method is important in each class
    }
    
    public function page1()
    {
        echo we are in "page1";
    }
    
    public function page2()
    {
        echo we are in "page2";
    }
    
    public function page_3()
    {
        echo 'page-3';
    }
}

// Route some methods from it
horus('router') -> any('/', 'Test2');
// Now each method works as a page .
// Now you can enter '/page1', '/page2', '/page_3', '/page-3', 'page-3.html', '/page1.php', '/index' and '/'
// You noticed that Horus Router converts '-' to '_' and ignore any '.extension' to be very easy

Horus Framework has built-in smart autoloader . by default it's registered using spl_autoload_register(), you can add your own, but here i'll speak about horus autoloader .
Horus Autoloader Converts any underscore and backslash to the system directory separator, based on the horus installation directory, so new Horus_View will converted to '/path/to/horus_installation/Horus/View.php' .


Examples:


    # say that we have the next directory structure
    /*
    
    ------------------------
        -\
        --\MyApp
        --\Horus
        --\index.php
        --\.htaccess
    ------------------------    
    
    # when you call "new MyApp_ClassName", then horus autoloader will
      load "\MyApp\ClassName.php" then start it.
    
    # or "new Horus_View" , then horus autoloader will
      load "\Horus\View.php" then start it.
    
    # or "use \MyApp\Namespace\File" , then horus autoloader will
      load "\MyApp\Namespace\File.php" then start it.
    
    # so you noticed that this autoloader is based on the directory name
      an if you changed the directory name, you will be in a problem, so to solve this
      you need to set a new path alias
      e.g: if you changed the name of "Horus" directory to "Core"
    */
    
    // tell horus that the new path of 'Horus' prefix is '\Core\'
    horus()->autoloadPathAlias('Horus', '\Core\');
    

Horus has built in views manager class that is very simple and easy .

Usage


    // after you included and started horus
    
    // start the view
    $view = new Horus_View;
    
    // set the views path and it's extension
    $view -> setup('path/to/views_dir', '.html');
    
    // add var to the view
    $view -> addVar('var', 'value');
    # or
    $view -> addVar(array('var' => 'value'));
    
    // remove a var
    $view -> unsetVar('var');
    
    // has the var 'var' ?
    $view -> hasVar('var'); // returns bool
    
    // load a view file(s) 'header, body' as string and pass array of vars to them
    $vars = array( 'var1' => 'val1', 'var2' => 'val2' );
    $v = $view->load('header, body', $vars);
    echo $v;
    # to display it directly
    $view->render('header, body', $vars);
    
    // NOTE: you can assign the $view var to horus directly, and use it noramlly
    horus()->view = $view;
    // horus()->view->render(....) or horus('view')->render(....);
    

Horus has build-in multi-language manager

Usage


    // after you included and started horus
    
    // start the view
    $lang = new Horus_Lang;
    
    // set the languages path and it's extension
    $lang -> setup('path/to/langs_dir', '.lang');
    
    // load a language file { the file must return an array contains keys => values }
    // say that we have lang-file "en.lang" then it's contents is
    /*
        <?php
            return array
            (
                'key1' => 'val1',
                'key2' => 'val2'
            );
        ?>
    */
    $lang->load('en');
    
    // add translations ( assoc-array )
    $lang -> add(array('key' => 'value'));
    
    // get a translation
    echo $lang->get('key');
    
    // translate full subject
    echo $lang->translate('my subject');
    

Horus comes with simple common helpers that will help you while developing .

function dump($var, $var_dump = false)
Print var in human readable way
By default it uses print_r + pre but if you like var_dump + pre
just set $var_dump to true .


function headeri($string, $replace = false, $http_response_code = null)
An improved function instead of header() uses the new http class .


function go($to, $using = 302)
Redirect to another page using 302|301|'html'|'js'
example
go('http://google.com', 'js:5') redirect using javascript after 5 seconds, you could write 'js' only
go('http://google.com', 'html:5') redirect using html after 5 seconds, you could write 'html' only
go('http://google.com', 302) redirect using http-302
go('http://google.com', 301) redirect using http-301


function cURL($url, array $curl_options = array())
Quick cURL connection, will return array of page content and page info (headers)
$url the url to connect to .
$curl_options array of curl options, default empty means (CURLOPT_RETURNTRANSFER => true)
example
$data = cURL('google');
echo 'content: ', $data['content'];
dump($data['info'])


function session_init($lifetime = 0)
Start new session (alternative to session_start())
$lifetime: the period (in sec) of the session, default 0 means 900 sec


function session_end()
Destroy session and free $_SESSION array .


function server($key = null)
get value from $_SERVER
example
echo server('request uri'); or echo server('request-uri'); or echo server('request_uri'); or echo server('request/uri'); or echo server('REQUEST_URI'); if $key is null will return all $_SERVER array


function isHttps()
check if the request is using HTTPS, return bool


function isAjax()
check if the request is under Ajax, return bool


function isApache()
check if the server is apache, return bool


function isCli()
check if the script run under Command line, return bool


function isCgi()
check if the script run under CGI, return bool


function uri($to = null)
Generate uri to an internal page in horus application


function asset($to = null)
Generate direct url to an asset file in horus application


function random_str($length = 5)
Generate random string with a certain length


function random_serial($serials_count = 1, $blocks_count = 5, $block_size = 5, $separaor = '-')
Generate random serial .
$serials_count: how many serials do you need ?
$blocks_count: how many blocks per serials ?
$block_size: size of each block ?
$separator: the blocks delimiter ?


function limit_words($subject, $offset, $limit, $ends = ' ...')
Limit subject based on words, e.g: you need only 5 words from the start of subject and end it with ...: echo limit_words('this is test statement and this is test', 0, 5)


function array_insert(array $into, mixed $new, int $position)
insert array or element into any position of another array

example:


        $into = array(1,2,3,6,7);
        $new = array(4, 5);
        $position = 3;
        $result = array_insert($into, $new, $position);
        // will be: array(1, 2, 3, 4, 5, 6, 7)
    


function horus($using = null)
to get horus instance

example:



        // 1)-
        horus()->view->render('header');
        // 2)-
        horus('view')->render('header);
    

function array_start(array $array)
to get the first element in an array

example:


        echo array_start(array(1,2,3,4,5));
        // will output '1'
    

function array_end(array $array)
to get the last element in an array

example:



        echo array_end(array(1,2,3,4,5));
        // will output '5'
    

function array_isset(array $array, array $keys)
check if the given $keys are fully exists in $array

example:



        echo array_isset(array(1,2,3,4,5), array(1,3));
        // will output '1'
        
        echo array_isset(array(1,2,3,4,5), array(1,8));
        // will output '0' or null
    

function array_unset(array $array, array $keys)
unset array of keys from an array

example:



        $new = array_unset(array('x'=> 1, 'y'=>2, 'xz'=>3), array('x', 'y'));
        // will remove $new will only be array('xz' => 3)
    

function define_array(array $defines)
just like define() but will work over an array

example:



        define_array(array(
            'DS' => DIRECTORY_SEPARATOR,
            'NAME' => 'HORUS_FRAMEWORK',
        ));
        echo DS;
        echo NAME;
    

function mempty()
check whether var(s) empty

example:



        if(mempty($_GET['key1'], $_GET['key2'], $_GET['key3'])) {
            echo 'empty';
        }
    

function halt($code = 200, $message = null)
exit application and set status code and show message

example:



        halt(404, 'not found');
        // or
        halt(404, horus()->errDocs()->e404);
    

array_get(array $input, $needle, $except = null)
Get elements from array or get all except some

example:



        $array = array(1,2,3,4,5,6,7,8,9);
        // get all
        dump( array_get($array, '*') );
        // get all except 1,2
        dump( array_get($array, '*', array(1,2)) );
        // get only 1,2
        dump( array_get($array, array(1,2)) );
    

function password_hash($password, $algo = PASSWORD_DEFAULT, array $options = array())
Horus introduces this api in any PHP 5 version not only PHP 5.5, you don't need to upgrade to PHP 5.5 :D
Creates a new password hash using a strong one-way hashing algorithm.
See More Here Here
function password_get_info($hash)
See More Here Here
function password_needs_rehash($hash, $algo = PASSWORD_DEFAULT, array $options = array())
See More Here Here
function password_verify($password, $hash)
See More Here Here
function paginate($data_size, $current_page, $limit = 5, $link_format = '?p=%d', $max_links = 5)
Smart Tiny Pagination Function, No need to ownload big class for small operation ;)

example:



        // how many results to paginate ?
        $count = 45;
        // how many results per page ?
        $perpage = 5;
        // what is the current page ?
        $current = $_GET['p']; // we used site.com/?p=xxx as our pager counter
        // what is the target link format ?
        // i'll use site.com/?p=xxx where xxx is an integer, we replace
        // the integer parameter with '%d'
        // e.g: for site.com/?go=news&new=blog&p=%d
        $target = '?p=%d';
        // how many links do you want ?
        // < 1 2 3 4 5 > those are 5 
        $links = 5;
        // now paginate
        $p = paginate($count, $current, $perpage, $target, $links);
        // now the var '$p' is an array contains
        // 1)- pages_count  (how many pages)
        // 2)- start        (the offset used for e.g: 'select .... limit $start, $limit')
        // 3)- limit        (the data limit = perpage)
        // 4)- links[]      (array contains generated links)
        //                  they are: next, prev, current, first, last and (from 1 to links_limit)
        $sql = "select * from table limit {$p['start']},{$p['start']}";
        $query = horus('db')->query($sql);
        while($row = horus('db')->fetch()) {
            // show data here
        }
        // show links ?
        foreach( $p['links'] as $name => $href) {
               echo sprintf(' %s     ', $href, $name);
        }
        // will print next prev first last current 1 2 3 4 5
        // note: if there is no prev, next, then the $href of them will be false
        // to help you detect it and make it "disabled=''"
    

function array_column (array $array , $column_key, $index_key = null)
Return the values from a single column in the input array
Also this function only exits in PHP >= PHP 5.5, But horus give it to you ^_^
See it Here
function maili($from, $to, $subject, $message, $name = '',array $headers = array())
mail-[i]-mproved function

        // yourmail
        $from = 'yourmail@gmail.com';
        // to (supports multiple)
        $to =  'to@gmail.com'; // or array('m1@gmail.com', 'm2@gmail.com', ... );
        // subject
        $subject = 'test';
        // message [supports html, and also it set to utf-8]
        $message = 'hi this is message';
        // name [will show in target mailbox from ] "Optional"
        $name = 'myname';
        // more headers ? assoc array of your custom headers
        $headers  = array('Content-Type'=>'text/html; charset=UTF-8'); // this is the default
        // now send [ returns bool ]
        dump(maili($from, $to, $subject, $message, $name, $headers));
    

events_listen($tag, $callback, $order = 0)
register new event
$tag : the event tag/place/category .
$callback : the event callback .
$order : the event order/periority { small number = heigh periority }
events_dispatch($tag, array $arguments = array())
run events under category/tag {$tag} and pass arguments if needed .
Returns the last dispatched value .
function events_all()
returns all registered events .
function session_started()
check if the session is started, returns bool .
array_assoc_get(array $input, $needle, $except = null)
Get elements { keys => values } from array or get all except some

example:



    $array = array( 'k1'=>'v1', 'k2'=>'v2', 'k3'=>'v3' );
    // get all
    dump( array_get($array, '*') );
    // get all except for 'k1', 'k2'
    // will return array('k1' => 'v1')
    dump( array_get($array, '*', array('k1', 'k2')) );
    // get only 'k1', 'k2'
    dump( array_get($array, array('k1', 'k2')) );

error documents


# start horus ...
$horus = new Horus();

# show an error page
$horus->errorDoc('error title', 'error escription');
# or get it and display it manully
echo $horus->errorDoc('error title', 'error escription', true);

# there are also some error documents shortcuts
echo $horus->errorDocs()->e400; // or
echo $horus->errorDocs()->e401; // or

// you can use any error from the next

/*****************

    'e400'
    'e401'
    'e402'
    'e403'
    'e404'
    'e405'
    'e406'
    'e500'
    'e502'
    'e503'
    'e504'

******************/

Horus Framework doesn't love any overhead so it extends PDO and simplified some things let's see it:


# start horus ...
$horus = new Horus;

# just like PDO to connect
$horus->db = new Horus_DB; // or horus()->db = ....
$horus->db->connect('dns', 'username', 'password', $options);

// OR

# Connect to mysql server
$horus->db->mysql('db server', 'db name', 'username', 'password');

# Connect to sqlite
$horus->db->sqlite('db_filepath');

# Connect to mssql {sql server} server
$horus->db->mssql('db server', 'db name', 'username', 'password');

# Connect to oracle server
$horus->db->oracle('db server', 'db name', 'username', 'password');

# Connect to postgre server
$horus->db->pgsql('db server', 'db name', 'username', 'password');

# create a query (improved function) 
# (and optionally pass array of binds inputs)
$horus->db->query(
    'select * from table where col1=? and col2 = ?', 
    array('value1', 'value2'
));

// fetch just what pdo does
var_dump($horus->db->fetchAll());

// Yes every thing from just from one object
// So i call it (PDO Improved) as it merged PDO with PDOStatement
// So you can access any method of them just from that object '$horus->db'



ORM

Horus Framework provides you a simple extensible ORM For the database
ORM is "Object Rational Mapper" for database operations, to simplify dealing with it .


// start horus
$horus = new Horus;

// use it
// you will need the horus_db construction
$horus->db = new Horus_DB;
$orm = new Horus_DB_ORM($horus->db);

// you can access any 'db' method from 'orm' too
$orm -> mysql('server', 'dbname', 'username', 'password');

// set the table
$users = $orm->on('users');

# insert ( single-insert )
// insert into users(name, city, icon) values(?, ?, ?)
// return bool
$users->insert(array
( 
    'name'  =>  'user name',
    'city'  =>  'user city',
    'icon'  =>  'user icon'
))->end();

// only show the generated sql statement ?
echo $users->insert(array
( 
    'name'  =>  'user name',
    'city'  =>  'user city',
    'icon'  =>  'user icon'
))->getSQL();

// show the inputs only ?
dump($users->getInputs());

# insert multiple users at one query (good for performance)
// insert multiple rows at once
// return bool
$users->minsert(array
(
    // into
    array('name', 'city', 'icon'),
    
    // values
    array('name 1', 'city 1', 'icon 1'),
    array('name 2', 'city 2', 'icon 2'),
    array('name 3', 'city 3', 'icon 3'),
    array('name 4', 'city 4', 'icon 4'),
    array('name 5', 'city 5', 'icon 5'),
    array('name 6', 'city 6', 'icon 6')
))->end(); 
// this is won't work for sqlite old versions that don't
// supports 'Values(?, ?),(?, ?),...', so for sqlite set 
// the seconde param to true, as following:
$users->minsert(array
(
    // into
    array('name', 'city', 'icon'),
    
    // values
    array('name 1', 'city 1', 'icon 1'),
    array('name 2', 'city 2', 'icon 2'),
    array('name 3', 'city 3', 'icon 3'),
    array('name 4', 'city 4', 'icon 4'),
    array('name 5', 'city 5', 'icon 5'),
    array('name 6', 'city 6', 'icon 6')
), true)->end(); 

# update
// return bool
$users->update(array
(
    'name' => 'new name',
    'icon' => 'new icon'
))->where('id = ?', 5)->end();

# or
// return bool
$users->update(array
(
    'name' => 'new name',
    'icon' => 'new icon'
))->where('id = ? and name = ?', array(5, 'old name'))->end();

# or
// return bool
$users->update(array
(
    'name' => 'new name',
    'icon' => 'new icon'
))->where('id = ? and name = ?')->inputs(array(5, 'old name'))->end();

# select
// return bool
$users->select('*')
                    ->where('id = ?', 5)
                    ->limit(1)
                    ->order('id', 'DESC')
                    ->end();
// now fetch, just like pdo, any fetch method
$users->fetchAll(PDO::FETCH_OBJ);

# delete
// return bool
$users->delete()->where('id' , 5)->end();

// you can also add a sql statement
$users->delete()->sql('where id = ?', 5)->end();
// or
$users->delete()->sql('where id = ?')->inputs(5)->end();

# you can add any feature !
# smart, advanced development
$users->multi_delete = function(array $ids){
    $inputs = $ids;
    $ids = array_fill(1, count($ids), '?');
    $ids = implode(', ', $inputs);
    
    horus()->orm->delete()->where('id in '.$ids);
    horus()->orm->inputs($inputs);
    
    return horus()->orm->on(horus()->orm->table);
    
    // NOTE: horus() function is only available from 
    // Version 1.3.0
};
// now use it
$users->multi_delete(array(1, 12, 3));

Horus provides you with simple ways to exted it easily without a hassle .
There are 2 ways {Events/Hooks } or { OOP Overloading }

Events/Hooks


/*

Those are horus hooks

----------------------------
horus.boot              ->  when horus starts
horus.before_dispatch   ->  before dispatch all routes
horus.after_dispatch    ->  after dispatch routes
horus.output            ->  to control the output { the output will be passed to all hooks }
horus.shutdown          ->  when horus shutsdown
----------------------------

*/

// edit the output
// horus passing the output as the first argument
// and the second (last) argument is contains the last value
// of the last dispatched event
events_listen( 'horus.output', function($output, $filtered){
    return ''.(empty($filtered) ? $output : $filtered); 
});

// new example for filtering
$txt = 'my text';

// add event (will edit on the $txt) so it will be the first arg
// but the last arg contains the value of last edited

event_listen('test-tag', function($default_text, $last_filtered){
    if(empty($last_filtered)) {
        return '<i>'.$default_text.'</i>';
    } else
        return '<i>'.$last_filtered.'</i>';
});

event_listen('test-tag', function($default_text, $last_filtered){
    if(empty($last_filtered)) {
        return '<b>'.$default_text.'</b>';
    } else
        return '<b>'.$last_filtered.'</b>';
});

// dispatch and edit it
// will show "<b><i>my text</i></b>"
echo events_dispatch('test-tag', $txt);

// stop with hello
events_listen('horus.boot', function(){
    die('hi');
});

# all events stored in $GLOBALS['horus_events'], so you can control them too

OOP Overloading



// assign var to horus
horus() -> my_var = 'my value';

// get var
echo horus()-> my_var;

// add method
horus()->method = function($txt){
    echo $txt;
};

// use method
horus()->method('hi'); // show hi

// use it as static
Horus::method('hi');

// unset var/method
unset(horus()->my_var);

// check if isset
isset(horus()->my_var);