Can I set a PHP class property from an existing variable?
I am trying to figure out how I want to handle settings in my PHP app. I have pretty much decide that I would like to开发者_如何学编程 use a Confg class file so it will be autoloaded and flexible in the future. Below is some stuff I was playing with.
I know you cannot set a variable to popluate a Constant so I then try to use a public static property.
Why can I not set public static $ip = $_SERVER['REMOTE_ADDR']; ??
<?php
// config.class.php
class Config
{
const URL = 'http://www.foo.com';
const DB_User = 'dbname';
public static $test = 'test string';
public static $ip = $_SERVER['REMOTE_ADDR'];
}
///////////////////////////////////////////////////////
//index.php
// works
echo Config::URL;
// works
echo Config::$test;
// DOES NOT WORK
echo Config::$ip;
?>
members must be initialized with a constant expression (like a string constant, numeric literal, etc). php will give a parse error if you try to initialize a member with a dynamic expression (like the value of a variable or a function call)...
this is unlike some other langs like python, or javascript which consider class definitions to be on par with executable expressions... so your idea here is very functional, but php doesn't support it now at least...
but there are some alternatives to deal with this:
add the initialization after the class definition:
class C {...}
C::$var = $_SERVER['REMOTE_ADDR'];
or have an init function:
function init()
{
if (self::$init === false) {
self::$var = $_SERVER['REMOTE_ADDR'];
self::$init = true;
}
}
C::init();
or with newer php you can use the __autoload() hook to do some static initializations...
Although this does not answer your question (jspcal answers it correctly), a quick solution that might fit your needs would to use the Singleton design pattern. Here is an alternative:
<?php
// config.class.php
class Config
{
/**
* Instance container
* @var Config
*/
private static $instance = null;
/**
* Constants container
* @var array
*/
private $constants = array(
'url' => 'http://www.foo.com/',
'db_user' => 'dbname'
);
/**
* Options container
* @var array
*/
private $options = array();
/**
* Don't allow outside initialization
*/
private function __construct()
{
// Set options (could load from external source)
$this->options = array(
'test' => 'test string',
'ip' => $_SERVER['REMOTE_ADDR']
);
}
/**
* Disable cloning
*/
private function __clone() { }
/**
* Get new instance of class
*/
public function getInstance()
{
if ( null === self::$instance ) {
self::$instance = new self();
}
return self::$instance;
}
/**
* Retrieve value with constants being a higher priority
* @param $key Key to get
*/
public function __get( $key )
{
if ( isset( $this->constants[$key] ) ) {
return $this->constants[$key];
} elseif ( isset( $this->options[$key] ) ) {
return $this->options[$key];
}
}
/**
* Set a new or update a key / value pair
* @param $key Key to set
* @param $value Value to set
*/
public function __set( $key, $value )
{
$this->options[$key] = $value;
}
}
///////////////////////////////////////////////////////
//index.php
// works
$config = Config::getInstance();
echo $config->url;
echo $config->test;
echo $config->ip;
Updated: Not sure if you want the constants / options with that kind of priority. It's just an example.
try to use define() to do that (give a constant!):
// config.class.php
define(REMOTE_ADDR, $_SERVER['REMOTE_ADDR']);
class Config
{
const URL = 'http://www.foo.com';
const DB_User = 'dbname';
public static $test = 'test string';
public static $ip = REMOTE_ADDR;
}
Not a direct answer to your question, but why don't you use a less hardcoded approach, e.g. a generic Config class you can reuse in your apps
// MyConfig.php
class MyConfig {
protected $_data;
public function __construct($path)
{
$config = include $path;
$this->_data = $config;
}
public function __get($val)
{
if(array_key_exists($val, $this->_data)) {
return $this->_data['val'];
} else {
trigger_error("Key $val does not exist", E_USER_NOTICE);
}
}
}
that you can fill from an array for a specific app
// app-config.php
return array(
'ip' => $_SERVER['REMOTE_ADDR'],
'url' => 'http://www.foo.com';
'db' => array(
'host' => 'foo.com',
'port' => 3306
),
'caching' => array(
'enabled' => false
)
);
and then use in your bootstrap like
$config = new MyConfig('/path/to/app-config.php');
This is not answering your question, but in my opinion, a better way to deal with configurations is actually to use a real configuration file, like an INI or XML file.
You could use e.g. the Zend Config class to read and write such files (and this class can even deal with a plain PHP array as configuration.
In the end this will make your code easier to maintain.
After reading other answers and comments you might also be interested in the Zend Registry class.
In general I would advice to use a framework or readymade components for such stuff. You don't need to reinvent the wheel and you can profit from the other's experience.
It won't work because PHP just doesn't allow it.
Generally I wouldn't suggest putting your app's config into a class (at least not in PHP), there are no real advantages in my opinion - better put it into a global array or so :)
PHP simply doesn't allow that. If you think about it, it doesn't make sense to have the REMOTE_ADDR as part of your configuration data anyway. You can consider it to be part of the request data, and not the application configuration.
As for your configuration, I would suggest using an .ini file for your configuration because PHP has a built-in INI parser (see the parse_ini_file function). This would be consistent with PHP's choice of INI file format for its own configuration (i.e., php.ini).
Check out this question, for example: What's Is the Best File Format for Configuration Files
The simple reason why you cannot assign $_SERVER['REMOTE_ADDR'] to the class attribute is this.
In PHP, Class attribute value can only be a data type and not a variable, and since $_SERVER is a global array variable, it can't be assigned to an attribute.
精彩评论