CodeIgniter hooks change behaviour without touching the core files

CodeIgniter’s execution flow has a fixed set of points where it will call your code — before the system loads, after the controller is constructed, after the response is sent. Registering there means a cross-cutting concern can live outside the controller hierarchy entirely, rather than in a MY_Controller that every controller must remember to extend.

// application/config/config.php
$config['enable_hooks'] = TRUE;

// application/config/hooks.php
$hook['post_controller_constructor'] = array(
    'class'    => 'MaintenanceGate',
    'function' => 'check',
    'filename' => 'MaintenanceGate.php',
    'filepath' => 'hooks',
);

The difference from a base controller is that a hook fires for every request, including the ones routed to controllers you did not write and did not think about — which is exactly what you want for a maintenance gate or an audit log, and exactly what you do not want for anything a single controller should own. post_controller_constructor is the useful point: it is the earliest one where get_instance() returns a loaded instance, so the session and the database are available. The cost is that the behaviour is now invisible from the controller, and the next person to read it will not find a hint that the hook exists.