Since Config::load()
is declared with preload
(which should imply static
)
it would be run once and its return value would be converted to OpCode so when
the following line of code runs during normal execution — such as on the web
for each page load — it would execute extremely fast and would not open nor
decode the config.json
file, since that would have been done a OpCode generation
time.
Last active
January 13, 2020 01:28
-
-
Save mikeschinkel/445ed6de242d6cdfdac93d5e9384820e to your computer and use it in GitHub Desktop.
Simple config class in PHP illustrating how a `preload` might work. In this example, the load() method uses the `preload` modifier on Line 38 of config.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
$config = Config::load(); | |
echo $config->get_value( Config::BAR ); // Prints 'Hello' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
class Config { | |
const FOO = 'foo'; | |
const BAR = 'bar'; | |
const BAZ = 'baz'; | |
private const _DEFAULTS = array( | |
self::FOO => 1, | |
self::BAR => 'Hello', | |
self::BAZ => false, | |
); | |
private const _FILEPATH = __DIR__ . '/config/config.json'; | |
/** | |
* @var self | |
*/ | |
private static $_instance; | |
/** | |
* @var array | |
*/ | |
private $_config; | |
/** | |
* `preload` would be run once and its returned value would be | |
* converting into OpCodes to be cached for subsequent page loads. | |
* | |
* This example uses `do{...}while(false)` to provide a context | |
* in which `break` can exit the context but this differs from | |
* using an early `return` because the default value still needs | |
* to be set. | |
* | |
* This example includes error handling but is not 100% robust | |
* since it is only an example and currently available PHP does | |
* not support `preload` so this can't be fully tested. | |
* | |
* @return self | |
*/ | |
preload function load():self{ | |
do { | |
$config = self::instance(); | |
if ( ! is_file( self::_FILEPATH ) ) { | |
break; | |
} | |
$json = file_get_contents( self::_FILEPATH ); | |
$values = json_decode( $json ); | |
if ( ! is_null( $values ) ) { | |
break; | |
} | |
if ( is_object( $values ) ) { | |
$values = (array) $values; | |
} | |
if ( ! is_array( $values ) ) { | |
break; | |
} | |
foreach( self::defaults() as $key => $default ) { | |
if ( isset( $values[ $key ] ) ) { | |
continue; | |
} | |
$values[ $key ] = $default; | |
} | |
$config->_config = $values; | |
} while ( false ); | |
if ( ! isset( $config->_config ) ) { | |
$config->_config = self::defaults(); | |
file_put_contents( self::_FILEPATH, | |
json_encode( $config->_config ) | |
); | |
$message = sprintf( 'config file %s does not exist; default config file written to disk.', | |
self::_FILEPATH | |
); | |
trigger_error( $message, E_USER_NOTICE ); | |
} | |
return $config; | |
} | |
/** | |
* @param string $key | |
* | |
* @return mixed|null | |
*/ | |
function get_value( string $key ) { | |
return $this->_config[ $key ] ?? null; | |
} | |
/** | |
* @return array | |
*/ | |
static function defaults():array { | |
return self::_DEFAULTS; | |
} | |
/** | |
* @return self | |
*/ | |
static function instance():self { | |
if ( ! isset( self::$_instance ) ) { | |
self::$_instance = new self(); | |
} | |
return self::$_instance; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment