Is it possible to run php method on property change? Like shown in the example below:
Class:
class MyClass
{
public MyProperty;
function __onchange($this -> MyProperty)
{
echo "MyProperty changed to " . $this -> MyProperty;
}
}
Object:
$MyObject = new MyClass;
$MyObject -> MyProperty = 1;
Result:
"MyProperty changed to 1"
Like #lucas said, if you can set your property as private within the class, you can then use the __set() to detect a change.
class MyClass
{
private $MyProperty;
function __set($name, $value)
{
if(property_exists('MyClass', $name)){
echo "Property". $name . " modified";
}
}
}
$r = new MyClass;
$r->MyProperty = 1; //Property MyProperty changed.
You can achieve this best by using a setter method.
class MyClass
{
private MyProperty;
public function setMyProperty($value)
{
$this->MyProperty = $value;
echo "MyProperty changed to " . $this -> MyProperty;
}
}
Now you simply call the setter instead of setting the value yourself.
$MyObject = new MyClass;
$MyObject -> setMyProperty(1);
This post is quite old, but I have to deal with the same issue and a typical class with multiple fields. Why using private properties ?
Here is what I implemented :
class MyClass {
public $foo;
public $bar;
function __set($name, $value) {
if(!property_exists('MyClass', $name)){ // security
return;
}
if ('foo' == $name) { // test on the property needed to avoid firing
// "change event" on every private properties
echo "Property " . $name . " modified";
}
$this->$name = $value;
}
}
$r = new MyClass();
$r->bar = 12;
$r->foo = 1; //Property foo changed.
var_dump($r);
/*
object(MyClass)[1]
public 'foo' => int 1
public 'bar' => int 12
*/
Using the magic method __set:
class Foo {
protected $bar;
public function __set($name, $value) {
echo "$name changed to $value";
$this->$name = $value;
}
}
$f = new Foo;
$f->bar = 'baz';
It may be a better and more conventional idea to use a good old-fashioned setter instead:
class Foo {
protected $bar;
public function setBar($value) {
echo "bar changed to $value";
$this->bar = $value;
}
}
$f = new Foo;
$f->setBar('baz');
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 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
Is any way to create class static var inside method?
something like this..
class foo {
public function bind($name, $value) {
self::$name = $value;
}
};
or is there other solution to bind variables to class and later use it without long and ugly syntax "$this->"
I'm not sure I understand the question. But if you'd like to attach variables at runtime, you could do this:
abstract class RuntimeVariableBinder
{
protected $__dict__ = array();
protected function __get($name) {
if (isset($this->__dict__[$name])) {
return $this->__dict__[$name];
} else {
return null;
}
}
protected function __set($name, $value) {
$this->__dict__[$name] = $value;
}
}
class Foo
extends RuntimeVariableBinder
{
// Explicitly allow calling code to get/set variables
public function __get($name) {
return parent::__get($name);
}
public function __set($name, $value) {
parent::__set($name, $value);
}
}
$foo = new Foo();
$foo->bar = "Hello, world!";
echo $foo->bar; // Prints "Hello, world!"
http://codepad.org/H9bz2uVp
Using self would result in a fatal error, as the property is undeclared. You would have to use $this which would then be accessible as a public variable:
<?php
class foo {
public function bind($name, $value) {
$this->$name = $value;
}
}
$foo = new Foo;
$foo->bind('bar','Hello World');
echo '<pre>';
print_r($foo);
echo $foo->bar;
echo '</pre>';?>
i have something like this:
class foo
{
//code
}
$var = new foo();
$var->newVariable = 1; // create foo->newVariable
$var->otherVariable = "hello, im a variable"; //create foo->otherVariable
i can get in class foo a list of all variables defined outside by user (newVariable, otherVariable,etc)? Like this:
class foo
{
public function getUserDefined()
{
// code
}
}
$var = new foo();
$var->newVariable = 1; // create foo->newVariable
$var->otherVariable = "hello, im a variable"; //create foo->otherVariable
var_dump($var->getUserDefined()); // returns array ("newVariable","otherVariable");
Thanks!.
Yes, using get_object_vars() and get_class_vars():
class A {
var $hello = 'world';
}
$a = new A();
$a->another = 'variable';
echo var_dump(get_object_vars($a));
echo '<hr />';
// Then, you can strip off default properties using get_class_vars('A');
$b = get_object_vars($a);
$c = get_class_vars('A');
foreach ($b as $key => $value) {
if (!array_key_exists($key,$c)) echo $key . ' => ' . $value . '<br />';
}
What is your goal? Imo it's not very good practice (unless you really know what you are doing). Maybe it's good idea consider create some class property like "$parameters" and then create setter and getter for this and use it in this way:
class foo {
private $variables;
public function addVariable($key, $value) {
$this->variables[$key] = $value;
}
public function getVariable($key) {
return $this->variables[$key];
}
public function hasVariable($key) {
return isset($this->variables[$key]);
}
(...)
}
$var = new foo();
$var->addVariable('newVariable', 1);
$var->addVariable('otherVariable', "hello, im a variable");
And then you can use it whatever you want, for example get defined variable:
$var->getVariable('otherVariable');
To check if some var is already defined:
$var->hasVariable('someVariable')
get_class_vars() http://php.net/manual/en/function.get-class-vars.php
You question is not clear though.
$var->newVariable = 1;
there are two possible contex of above expression
1) you are accessing class public variables.
like
class foo
{
public $foo;
public function method()
{
//code
}
}
$obj_foo = new foo();
$obj_foo->foo = 'class variable';
OR
2) you are defining class variable runtime using _get and _set
class foo
{
public $foo;
public $array = array();
public function method()
{
//code
}
public function __get()
{
//some code
}
public function __set()
{
// some code
}
}
$obj_foo = new foo();
$obj_foo->bar= 'define class variable outside the class';
so in which context your question is talking about?
Can we dynamically create and initialize an object in PHP?
This is the normal code:
class MyClass{
var $var1 = null;
var $var2 = null;
.
.
public function __construct($args){
foreach($args as $key => $value)
$this->$key = $value;
}
}
---------------------
$args = ($_SERVER['REQUEST_METHOD'] == "POST") ? $_POST : $_REQUEST;
$obj = new MyClass($args);
The above code works fine. Please note that the names of REQUEST parameters are accurately mapped with the members of class MyClass.
But can we do something like this:
$class = "MyClass";
$obj = new $class;
If we can do like this, then can we initialize $obj by using $args.
According to this post, $obj = $class should work. But it does not work for me. I tried get_class_vars($obj). It threw an exception.
Thanks
It's more a comment, but I leave it here more prominently:
$class = "MyClass";
$obj = new $class($args);
This does work. See newDocs.
You have to overload some other magic methods:
__get (a method that gets called when you call object member)
__set (a method that gets called when you want to set object member)
__isset
__unset
Please see this codepad to see your code rewritten to work with what you want:
<?php
class MyClass{
var $properties = array();
public function __construct($args){
$this->properties = $args;
}
public function __get($name) {
echo "Getting '$name'\n";
if (array_key_exists($name, $this->properties)) {
return $this->properties[$name];
}
return null;
}
}
$args = array("key1" => "value1", "key2" => "value2");
$class = "MyClass";
$obj = new $class($args);
echo "key1:". $obj->key1;
?>
You can use Reflection to instanciate an object with parameters.
<?php
class Foo {
protected $_foo;
protected $_bar;
public function __construct($foo, $bar)
{
$this->_foo = $foo;
$this->_bar = $bar;
}
public function run()
{
echo $this->_foo . ' ' . $this->_bar . PHP_EOL;
}
}
$objectClass = 'Foo';
$args = array('Hello', 'World');
$objectReflection = new ReflectionClass($objectClass);
$object = $objectReflection->newInstanceArgs($args);
$object->run();
See Reflection on php manual.