How its done in CI's case is that they heavily rely on passing stuff by reference (singleton), so calling $this->load->model('person')
invokes the person model and assigns it back into the controller.
You can see exactly how its done by looking at the source of the project on GitHub.
But in a nutshell:
<?php
// https://github.com/bcit-ci/CodeIgniter/blob/635256265a38e655c00f4415d5f09700f28c5805/system/core/Common.php#L140
function load_class($class) {
return (new $class());
}
// https://github.com/bcit-ci/CodeIgniter/blob/b862664f2ce2d20382b9af5bfa4dd036f5755409/system/core/CodeIgniter.php#L316
function &get_instance() {
return CI_Controller::get_instance();
}
// https://github.com/bcit-ci/CodeIgniter/blob/b862664f2ce2d20382b9af5bfa4dd036f5755409/system/core/Loader.php#L359
class CI_Loader
{
public function model($model, $name = '', $db_conn = FALSE)
{
$class = $model.'Model';
$CI =& get_instance();
$CI->{$model} = new $class;
}
}
// https://github.com/bcit-ci/CodeIgniter/blob/b862664f2ce2d20382b9af5bfa4dd036f5755409/system/core/Controller.php#L52
class CI_Controller {
private static $instance;
public function __construct()
{
self::$instance =& $this;
$this->load =& load_class('CI_Loader');
}
/**
* Get the CI singleton
*
* @static
* @return object
*/
public static function &get_instance()
{
return self::$instance;
}
}
// your models
class fooModel {
public $foo;
}
class barModel {
public $bar;
}
// your controller
class Controller extends CI_Controller {
public function indexAction()
{
$this->load->model('foo');
$this->load->model('bar');
}
}
// instance container
$app = (new class{});
$app->controller = new Controller();
// loaded by router
$app->controller->indexAction();
print_r($app);
Result (ignoring error):
class@anonymous Object
(
[controller] => Controller Object
(
[load] => Loader Object
(
)
[foo] => fooModel Object
(
[foo] =>
)
[bar] => barModel Object
(
[bar] =>
)
)
)
https://3v4l.org/fPCK3