A lot of posters have given beating around the bush answers ... sorry guys ... it's true.
The common way to take care of it is with Dependency Injection. Taking your class
class Layout {
public static function render($file, $vars) {
global $config, $mysql_db;
mysqli_query($mysql_db, "SELECT * FROM users");
}
}
You have a dependency on $config, $mysql_db;
Your class depends on them. Typically you would Inject these into the constructor like this.
protected $Mysqli;
protected $config;
public function __construct(array $config, Mysqli $Mysqli){
$this->config = $config;
$this->Mysqli = $mysqli;
}
The issue you have is that the method itself is static, so that bypasses the guarantee that the constructor was called. You can just call the method directly. If possible I would change this to not be static.
But if you insist on keeping it static, then there is a few common ways to solve this, and it depends what the rest of the class looks like. For these I will ignore $config
(for the most part) it's not used and it's not clear how it's used or what it's used for (I'm assuming it's for the database). I will also use the Object interface to Mysqli
instead of the procedural one.
The most obvious way it to stick them in the method call
public static function render($file, $vars, Mysqli $Mysqli) {
$Mysqli->query("SELECT * FROM users");
}
You can check when the method is called and connect
protected static $Mysqli;
public static function connect(){
//this has the obvious problem of getting the connection info.
$config = require 'config.php';
if(!is_array($config)) throw new Exception('Bad config..'); //etc.
self::$Mysqli = new mysqli(
$config['dbhost'],
$config['dbuser'],
$config['dbpass'],
$config['dbname']
);
}
public static function render($file, $vars) {
if(!$Mysqli) self::connect();
self::$Mysqli->query("SELECT * FROM users");
}
//config.php would look like this
<?php
return [
'dbname' => 'database',
'dbuser' => 'username',
'dbpass' => 'password',
'dbhost' => 'host'
];
This works but it may not be Ideal because now your class is responsible for an external file config.php
which if it doesn't exist will cause issues.
You can use a singleton pattern if this class is all static methods. This saves a reference to the class instance (it's self) in a static property. Then when you call getInstance
it always returns the same instance, that is way it is called a single
ton
class Layout {
//saves a reference to self
private static $instance;
protected $Mysqli;
final private function __construct(Mysqli $Mysqli){
if(!$Mysqli) throw new Exception('Instance of Mysqli required');
$this->Mysqli = $Mysqli;
}
final private function __clone(){}
final private function __wakeup(){}
public static function getInstance(Mysqli $Mysqli = null)
{
if (!self::$instance)
self::$instance = new self($Mysqli);
return self::$instance;
}
public function render($file, $vars) {
self::$Mysqli->query("SELECT * FROM users");
}
}
$Layout = Layout::getInstance();
$Layout->render($file, $vars);
The problem with this is the first call the Mysqli
class (or config or whatever) is required, but on subsequent calls it's not. You may or may not know ahead of time that its the first call. But again you could load the config from a file in this example too.
You'll also notice a few methods are Final private
this is to prevent overloading and calling them from outside the class.
I also have a trait for Singleton and Multiton (singleton container, multiple Singletons) that I put up on GitHub and Composer, you can find that here
https://github.com/ArtisticPhoenix/Pattern/
Each has it's advantages and disadvantages.
P.S. I just typed these all out on this page, so I didn't test any of them but the theory is sound....