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
Related
Does anyone know of an efficient technique in PHP to auto assign class parameters with identically named __construct() method arguments?
For instance, I've always thought it was highly inefficient to do something like the following:
<?php
class Foo
{
protected $bar;
protected $baz;
public function __construct($bar, $baz)
{
$this->bar = $bar;
$this->baz = $baz;
}
}
I'm wondering if there's a better/more efficient way/magic method to auto-assign class properties with identically named method parameters.
Thanks,
Steve
PHP 8
Constructor Promotion
function __construct(public $bar, public $baz) {}
PHP 5
function _promote(&$o) {
$m = debug_backtrace(0, 2)[1];
$ref = new ReflectionMethod($m['class'], $m['function']);
foreach($ref->getParameters() as $i=>$p) {
$o->{$p->name} = $m['args'][$i] ?? $p->getDefaultValue();
}
}
class Foo {
function __construct($bar, $baz) {
_promote($this);
}
}
I think this way is a pretty generally accepted way to do it, although you could make getters and setters. Or, if you're looking for magic methods in php: http://php.net/manual/en/language.oop5.magic.php
Not in a constructor. You can always wrap your properties into an array, instead, and only have a single property that needs to be set:
<?php
class SomeClass
{
protected $data = [];
public function __construct(array $data = [])
{
$this->data = $data;
}
public function getData()
{
return $this->data;
}
}
$params = ['bar' => 'bar', 'baz' => 'baz'];
$someClass = new SomeClass($params);
echo $someClass->getData()['bar'] . PHP_EOL;
There is the magic method __set, but it is only called when attempting to write data to inaccessible properties:
<?php
class SomeClass
{
protected $data = [];
public function __construct(array $data = [])
{
$this->data = $data;
}
public function __set($name, $value)
{
$this->data[$name] = $value;
}
public function __get($name)
{
if(isset($this->data[$name])) {
return $this->data[$name];
}
return null;
}
}
$class = new SomeClass;
$class->bar = 'bar';
$class->baz = 'baz';
echo $class->bar . PHP_EOL . $class->baz . PHP_EOL;
If your class is starting to have a lot of parameters being passed in to the constructor, it may be a sign that your class is getting too big and trying to do too much. A refactoring may be in order.
I want to declare a variable inside a class with an unknown name
class Example {
function newVar($name, $value) {
$this->$name = $value;
}
}
And I want to use it that way
$c = new Example();
$c->newVar('MyVariableName', "This is my Value");
echo($c->MyVariableName);
The Important thing is, that I do not know the name of the variable. So I cannot put a public $MyVariable inside the class.
Is that in anyway possible? and if yes, can i do this with different scopes (private, protected, public) ?
U should use magic methods __get and __set (example without checking):
class Example {
private $data = [];
function newVar($name, $value) {
$this->data[$name] = $value;
}
public function __get($property) {
return $this->data[$property];
}
public function __set($property, $value) {
$this->data[$property] = $value;
}
}
$c = new Example();
$c->newVar('MyVariableName', "This is my Value");
echo($c->MyVariableName);
// This is my Value
$c->MyVariableName = "New value";
echo($c->MyVariableName);
// New value
See http://php.net/manual/en/language.oop5.magic.php
If i am understanding this correctly you can tweak a little bit by using key value array
class Example {
private $temp;
function __construct(){
$this->temp = array();
}
function newVar($name, $value) {
$this->temp[$name] = $value;
}
function getVar($name){
return $this->temp[$name];
}
}
$c = new Example();
$c->newVar('MyVariableName', "This is my Value");
echo($c->getVar('MyVariableName'));
Instead of using private you can use protected as well.
Your looking for magic calling. In PHP you can use the __call() function to do stuff like that. Have a look here: http://www.garfieldtech.com/blog/magical-php-call
Off the top of my head, something like
function __call($vari, $args){
if(isset($this->$vari){
$return = $this->$vari;
}else{
$return = "Nothing set with that name";
}
}
This will also work for private, protected and public. Can also use it to call methods as required in a 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 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
How can i perform a function once a variable's value has been set?
say like
$obj = new object(); // dont perform $obj->my_function() just yet
$obj->my_var = 67 // $obj->my_function() now gets run
I want the object to do this function and now having to be called by the script.
Thanks
EDIT
my_var is predefined in the class, __set is not working for me.
Use a private property so __set() is invoked:
class Myclass {
private $my_var;
private $my_var_set = false;
public function __set($var, $value) {
if ($var == 'my_var' && !$this->my_var_set) {
// call some function
$this->my_var_set = true;
}
$this->$var = $value;
}
public function __get($var, $value) {
return $this->$name;
}
}
See Overloading. __set() is called because $my_var is inaccessible and there is your hook.
I'd recommend to create a setter function for $obj and include the relevant function call there. So basically your code would look somehow like this:
$obj = new ClassOfYours();
$obj->setThatValue("apple");
Of course you would have to take care that all assignments to ThatValue need to be
done through that setter in order make it work properly. Assuming that you're on php5 I'd set that property to private, so all direct assignments will cause an runtime error.
A good overview about OOP in php can be found in this article on devarticles.com.
HTH
To acheive exactly what you describe, you'd have to use a magic setter.
class ObjectWithSetter {
var $data = array();
public function my_function() {
echo "FOO";
}
public function __set($name, $value) {
$this->data[$name] = $value;
if($name == 'my_var') {
$this->my_function();
}
}
public function __get($name) {
if (array_key_exists($name, $this->data)) {
return $this->data[$name];
}
$trace = debug_backtrace();
trigger_error(
'Undefined property via __get(): ' . $name .
' in ' . $trace[0]['file'] .
' on line ' . $trace[0]['line'],
E_USER_NOTICE);
return null;
}
/** As of PHP 5.1.0 */
public function __isset($name) {
return isset($this->data[$name]);
}
public function __unset($name) {
unset($this->data[$name]);
}
}
Assuming you want to call my_function() once you set a value, that case you can encapsulate both the operations into one. Something like you create a new function set_my_var(value)
function set_my_var(varvalue)
{
$this->my_var = varvalue;
$this->my_function();
}