I have class with a static method. The static method returns a private static stdClass object.
myclass::get() // returns stdClass object
myclass::get()->name // name is hardcoded into the class
How would I change name's value like:
myclass::get()->name = 'bob';
and have it set?
I tried returning the object like:
return &self::$static_object;
But that throws syntax errors.
What can i do?
EDIT posted code for clarification
final class config {
private static $configs = array();
public static function get($config_name) {
if (isset($configs[$config_name])) {
return self::$configs[$config_name];
}
$file = __get_file_exists(M_CONFIGS . $config_name, 'conf.');
if ($file) {
$config = self::__scope_include($file);
if (!is_array($config) && !$config instanceof stdClass) {
/*
*
*
* FIX
*
*
*
*/
die('ERROR config.php');
}
return self::$configs[$config_name] = self::__to_object($config);
}
}
private static function __scope_include($file) {
return include $file;
}
private static function __to_object($config) {
$config = (object) $config;
foreach ($config as &$value) {
if (is_array($value)) {
$value = self::__to_object($value);
}
}
return $config;
}
}
echo config::get('people')->name; //dave
config::get('people')->name = 'bob';
echo config::get('people')->name; // should be bob, is dave
Returning by reference in the get() method should do the trick:
public static function &get() {
return self::$static_object;
}
But, I think you should revisit your design, as this kind of coding is highly frowned upon and will cause maintenance and testability headaches down the road.
You missed self in if (isset($configs[$config_name])) {. It should be
if (isset(self::$configs[$config_name])) {
return self::$configs[$config_name];
}
Otherwise each time you call config::get('people'), you will be reading your config file which most likely returns an array and convert it to an object before returning it. Any changes you make to the object in self::$configs[$config_name] are overwritten by the newly created object.
What you are doing and the answer from drrcknlsn break Encapsulation. That is bad.
The correct way to do this is to create a setter method.
public static function set($key, $value) {
// set $config property...
}
Related
I was wondering if you could get the class name and property name from a property reference in PHP?
class Test {
public static $TestProp;
}
GetDoc(& Test::$TestProp);
function GetDoc($prop) {
$className = getClassName($prop);
$propertyName = getPropertyName($prop);
}
what I'm looking for is if it is possible to create the functions getClassName and getPropertyName?
What you want is basically not possible; a property doesn't know its parent structure.
The only sane thing I could think of is to use reflection for it:
class Test
{
public static $TestProp = '123';
}
//GetDoc(& Test::$TestProp);
GetDoc('Test', 'TestProp');
function GetDoc($className, $propName)
{
$rc = new ReflectionClass($className);
$propValue = $rc->getStaticPropertyValue($propName);
}
Within the Test class you could use __CLASS__ as a convenient reference for the class name.
I have figured out the way to get this to work there is a lot of magic that goes on just to get this to work, but in my case it's worth it.
class Test {
private $props = array();
function __get($name) {
return new Property(get_called_class(), $name, $this->props[$name]);
}
function __set($name, $value) {
$props[$name] = $value;
}
}
class Property {
public $name;
public $class;
public $value;
function __construct($class, $name, $value) {
$this->name = $name;
$this->class = $class;
$this->value = $value;
}
function __toString() {
return $value.'';
}
}
function GetClassByProperty($prop) {
return $prop->class.'->'.$prop->name;
}
$t = new Test();
$t->Name = "Test";
echo GetClassByProperty($t->Name);
this example yes I know it's complex, but it does the job how I'd want it to, will print out "Test->Name" I can also get the value by saying $prop->value. If I want to compare the value to another object I can simply do this:
if($t->Name == "Test") { echo "It worked!!"; }
hope this isn't too confusing but it was a fun exploration into PHP.
Php have a build in function called get_class
How can I figure out in what class a reference to a variable was initiated (and currently exists)?
Example:
<?php
class MyClass {
public $array = array(
"this",
"is",
"an",
"array"
);
}
$class = new MyClass();
$arrayReference = &$class->array;
GetClassForVariable($arrayReference); //Should return "MyClass"
?>
My best bet is some kind of Reflection, but I haven't found any functions that seem suitable for this.
Edit:
A better suited example for what I want is the following:
<?php
class API_Module {
public $module;
public $name;
private $methods = array();
public function __construct($module, $name) {
$this->module = $module;
$this->name = $name;
$this->methods["login"] = new API_Method($this, "login", "Login");
}
public function GetMethod($method) {
return $this->methods[$method];
}
public function GetURL() {
return $this->module; //Should return "session"
}
}
class API_Method {
public $method;
public $name;
private $parentReference;
private $variables = array();
public function __construct(&$parentReference, $method, $name) {
$this->parentReference = $parentReference;
$this->method = $method;
$this->name = $name;
$this->variables["myvar"] = new API_Variable($this, "myvar");
}
public function GetURL() {
return $this->GetParentURL() . "/" . $this->method; //Should return "session/login"
}
public function GetVariable($variableName) {
return $this->variables[$variableName];
}
private function GetParentURL() {
// Need to reference the class parent here
return $this->parentReference->GetURL();
}
}
class API_Variable {
public $name;
private $parentReference;
public function __construct(&$parentReference, $name) {
$this->parentReference = $parentReference;
$this->name = $name;
}
public function GetURL() {
return $this->GetParentURL() . "/" . $this->name; //Should return "session/login/myvar"
}
private function GetParentURL() {
// Need to reference the class parent here
return $this->parentReference->GetURL();
}
}
$sessionModule = new API_Module("session", "Session");
var_dump($sessionModule->GetMethod("login")->GetVariable("myvar")->GetURL()); //Should return "session/login/myvar"
?>
Now, this works fine, but I'd love to be able to do this without using $parentReference in every single subvariable. It might not be possible, but I'd love to know whether it is or not.
For your example:
$class = new MyClass();
$arrayReference = &$class->array;
GetClassForVariable($arrayReference); //Should return "MyClass"
to find out to which variable originally the alias $arrayReference refers to is not possible in PHP. There is no function available resolving the aliases.
Additionally $class->array is just a variable on it's own. So you would also need to find out based on a value in which class it was defined. That is not possible as well, similar to that PHP does not offer anything to resolve a variable alias, it also does not offer anything to learn about the definition of a variable.
So in short PHP does not have a ReflectionVariable class available ;) I wonder if it is even possible.
The get_class() function should work:
http://php.net/manual/en/function.get-class.php
I agree with GRoNGoR that you shouldn't need to get the parent class of a property of an instantiated object. You could instead just get the name of the class before accessing the property. For example:
$class = new MyClass();
$parent_class = get_class($class); // returns "MyClass"
$arrayReference = &$class->array;
Not sure why you'd need the parent class of the property when you have the object instance and can easily get the parent class from there.
I have a php singleton session class as follows.
class Session {
static private $_instance = NULL;
private function __construct()
{
session_start();
}
/**
* Prevents the class from being cloned
* #return NULL
*/
private function __clone() { }
/**
* Returns the singleton instance of this class
* #return Session
*/
public static function getInstance()
{
if (!self::$_instance) {
self::$_instance = new Session();
}
return self::$_instance;
}
public function __get($key) {
if (isset($_SESSION[$key])) {
return $_SESSION[$key];
}
return NULL;
}
public function __set($key, $value)
{
$_SESSION[$key] = $value;
}
public function __isset($key) {
return isset($_SESSION[$key]);
}
public function __unset($key) {
unset($_SESSION[$key]);
}
}
I can create an object as follows
$session = Session::getInstance();
$session->name = 'some name';
I can also get the value like
echo $session->name;
The problem is, i want to pass an array to this object and it is not working. for example, i wan to set something like
$_SESSION['user']['data'] = array('name'=>'some name',"empId"=>'123');
I am trying like this.
$session->['user']['data'] = array('name'=>'some name',"empId"=>'123');
but it is not working. Could you please suggest what is wrong.
The workaround in this case would be to use:
public function &__get($key) {
if (isset($_SESSION[$key])) {
return & $_SESSION[$key];
}
return NULL;
}
You need to modify the __get() method, because an assignment like
$session->user['data'] = ...
will actually retrieve the [user] key, and then try to assign a new subarray [data] to that temporary array result.
Also note that $session->['user']['data'] is invalid syntax. You either need $session->user['data'] or $session->{'user'}['data'].
Anyway, I think it is probably not a good idea to use a wrapper if you often want to do assignments like that. (I do actually have something very similar.)
$session->user = array('data' => array('name'=>'some name',"empId"=>'123'));
Make sure you don't overwrite anything else in user you want to keep
I want to create properties that are set to mysql data.
class MyClass{
private $a = $r['a'];
private $b = $r['a'];
private $c = $r['c'];
}
I know this is incorrect syntax but I want you to get the idea.
I could create a method that returns a requested mysql data, but I don't want the function to be called for every single row.
You need to implement the magic method __get.
Something like:
class MyClass {
protected $_row = array();
public function __get( $name )
{
if (array_key_exists($name, $this->_row)) {
return $this->_row[$name];
}
return null;
}
public function __isset( $name )
{
return array_key_exists($name, $this->_row);
}
}
And you could used as:
$obj = new MyClass();
$obj->load(); // Or any method to load internal data
echo $obj->a . $obj->b;
Why reinvent the wheel ?
check this mysqli_result::fetch_object
In a lot of my PHP classes, I have this code:
private $strError = "";
private $intErrorCode = NULL;
private $blnError = FALSE;
public function isError() {
return $this->blnError;
}
public function getErrorCode() {
return $this->intErrorCode;
}
private function setError( $strError, $intErrorCode = NULL ) {
$this->blnError = TRUE;
$this->intErrorCode = $intErrorCode;
$this->strError = $strError;
}
The point is so that outside code can know if an object has an error state, what the string of the error is, etc. But to have this exact code in a bunch of different classes is repetitious!
I'd love to have a dual-extension where I could do
class childClass extends parentClass, error {
...
}
And have those properties and methods inborn, But PHP doesn't support multiple inheritances. What I'm thinking about doing is creating an error class that exists inside each class. If I make it public, I can call it directly through the object
if ( $myObject->error->isError() ) {...}
but wouldn't that also make its error status settable from outside the containing class,
$myObject->error->setError("I shouldn't be doing this here");
which I would rather avoid?
Or I could write 'gateway' functions in the containing class, which do the appropriate calls on the error object, and prevent setting the error status from outside,
class childClass extends parentClass {
private $error;
public function __construct(...) {
...
$error = & new error();
...
}
public function isError() {...}
public function getError() {...}
public function getErrorCode() {...}
private function setError() {...}
...
}
but that leads to (some of) the code duplication that I'm trying to avoid.
What's the optimal solution here? I'm trying to have functionality for error statuses for a number of objects, so that the outside world can see their error state, with minimal repetition.
Use composition instead of inheritance.
class Errors {
private $strError = "";
private $intErrorCode = NULL;
private $blnError = FALSE;
public function isError() {
return $this->blnError;
}
public function getErrorCode() {
return $this->intErrorCode;
}
private function setError( $strError, $intErrorCode = NULL ) {
$this->blnError = TRUE;
$this->intErrorCode = $intErrorCode;
$this->strError = $strError;
}
}
And now use a private instance variable to refer to it:
class childClass extends parentClass {
private $errors = new Errors();
...
}
The private visibility prevents you from referencing $errors outside of the class.
There's also no need to create isError(), getError(), etc. inside childClass (and therefore no need to worry about code duplication). Simply call $this->errors->isError(), $this->errors->getError(), etc. If you still wanted to require those methods to be implemented though, as suggested below, you could specify an interface.
You could also abuse the __call magic method to do the same thing:
public function __call($name, array $arguments) {
$name = strtolower($name);
if (isset($this->methods[$name])) {
array_unshift($arguments, $this);
return call_user_func_array($this->methods[$name], $arguments);
}
throw new BadMethodCallException('Method does not exist');
}
Note that I said abuse... Ideally, I'd think of a different architecture rather than having all these "common methods" everywhere. Why not use an exception instead of checking $foo->isError? If that's not appropriate, why not decorate a class?
class Errors
protected $object = null;
public function __construct($object) {
$this->object = $object;
}
public function __call($method, array $arguments) {
$callback = array($this->object, $method);
if (is_callable($callback)) {
return call_user_func_array($callback, $arguments);
}
throw new BadMethodCallException('Method does not exist');
}
public function __get($name) { return $this->object->$name; }
public function __set($name, $value) { $this->object->$name = $value; }
// Your methods here
public function isInstance($name) { return $this->object instanceof $name; }
}
Then just "wrap" your existing object in that class:
$obj = new Errors($obj);
$obj->foo();
As of PHP 5.4, you can use Traits.
For example you could make Trait called ErrorTrait like this:
trait ErrorTrait {
private $strError = "";
private $intErrorCode = NULL;
private $blnError = FALSE;
public function isError() {
return $this->blnError;
}
public function getErrorCode() {
return $this->intErrorCode;
}
private function setError( $strError, $intErrorCode = NULL ) {
$this->blnError = TRUE;
$this->intErrorCode = $intErrorCode;
$this->strError = $strError;
}
}
Then you would define your child class like this:
class childClass extends parentClass {
use ErrorTrait;
...
}
Traits work basically like copy/paste so all of the code in the trait would be available within the class (without the code duplication).