For this there is a pattern / approach - I don’t know how to correctly name: Lazy Loading . Its meaning is that an object performs its most resource-intensive logic only when it is requested for the first time. For example, in your case on the line:
$subject = index::list_subject(); // Массив с предметами
There should be no queries in the database, and in $ subject, instead of an array, the object to be iterated should be returned. Then at the first iteration in the current iterator method, you need to make this very query in the database to select the list.
protected $_list = []; protected $_initalized = false; public function current() { if (!$this->_initalized){ $this->_list = $this->_loadSomeListFromDB(); $this->_initalized = true; } return $this->_list[$this->position]; }
But the lazy approach spawns additional logic where it is used. To avoid this, a Lazy container is introduced. For example, it is called Restore, or ServiceManager - everything Lazy is encapsulated in a container. For example, this is how we initialize the connection to the database in ServiceManager:
ServiceManager::addServiceCallback('db', function() use ($dbUser, $dbPassword, $dbHost){ return new PDO('mysql:host='.$dbHost.';dbname=myproject', $dbUser, $dbPassword); })
and then when the code is called for the first time
$rows = ServiceManager::get('db')->query('SELECT * from FOO');
The db service is initialized, and all subsequent calls to the ServiceManager::get('db') will be taken from the already initialized db service. An example of a good Lazy container implementation: Zend 2 ServiceManager
PS What does not necessarily singleton - mark, because they are not very fashionable now.