Skip to content

Instantly share code, notes, and snippets.

@mikeschinkel
Last active January 13, 2020 01:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mikeschinkel/445ed6de242d6cdfdac93d5e9384820e to your computer and use it in GitHub Desktop.
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

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.

<?php
$config = Config::load();
echo $config->get_value( Config::BAR ); // Prints 'Hello'
<?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