PHP Create class variables - php

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>';?>

Related

How do I set PHP class properties with construct() arguments automatically?

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.

Php run method on property change

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');

Special class value in PHP

Some code:
class MyClass
{
public function __get($key)
{
return $this[$key];
}
public function __set($key, $value)
{
$this[$key] = $value;
}
}
$m = new MyClass();
$m->name = 'This is my class.';
OR
$m['name'] = 'This is my class.';
But not working. Somebody can help me?
In order to be able to access values in your class using array access, you have to implement the ArrayAccess interface. In order to also arbitrary property names dynamically, copy the sample code from that page. Once you've implemented the ArrayAccess methods your __get and __set will work as-is.
<?php
class obj implements arrayaccess {
private $container = array();
public function __construct() {
$this->container = array(
"one" => 1,
"two" => 2,
"three" => 3,
);
}
public function offsetSet($offset, $value) {
if (is_null($offset)) {
$this->container[] = $value;
} else {
$this->container[$offset] = $value;
}
}
public function offsetExists($offset) {
return isset($this->container[$offset]);
}
public function offsetUnset($offset) {
unset($this->container[$offset]);
}
public function offsetGet($offset) {
return isset($this->container[$offset]) ? $this->container[$offset] : null;
}
public function __get($key) {
return $this[$key];
}
public function __set($key, $value) {
$this[$key] = $value;
}
}
$foo = new obj();
$foo->pill = 123;
var_dump($foo->pill);
The problem you are having is that inside the __get and __set methods, you are accessing the properties as an array. You need to use $this->$key instead of $this[$key].
class MyClass
{
public function __get($key)
{
return $this->$key;
}
public function __set($key, $value)
{
$this->$key = $value;
}
}
$m = new MyClass();
echo "before set: \n";
var_dump($m);
$m->foo = "bar";
echo "after set: \n";
var_dump($m);
Example: http://codepad.viper-7.com/oNLbzq
Try this approach
class MyClass
{
private $m_var_data = array();
public function __set($p_name, $p_value)
{
$this->m_var_data[$p_name] = $p_value;
}
public function __get($p_name)
{
if (array_key_exists($p_name, $this->m_var_data))
{
return $this->m_var_data[$p_name];
}
}
}
$m = new MyClass();
$m->name = 'This is my class.';
In order to create a new property, you should do this:
class MyClass
{
private $data = array();
public function __set($name, $value)
{
echo "Setting '$name' to '$value'\n";
$this->data[$name] = $value;
}
public function __get($name)
{
echo "Getting '$name'\n";
if (array_key_exists($name, $this->data)) {
return $this->data[$name];
}
}
}
Then you can overload properties as you want in your example.
This link can give you more references:
http://www.php.net/manual/pt_BR/language.oop5.overloading.php#language.oop5.overloading.members

get a list of all variables defined outside a class by user

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?

Working with __get() by reference

With an example class such as this:
class Test{
public function &__get($name){
print_r($name);
}
}
An instance of Test will kick back output as such:
$myTest = new Test;
$myTest->foo['bar']['hello'] = 'world';
//outputs only foo
Is there a way I can get more information about what dimension of the array is being accessed, showing me (from the previous example) that the bar element of foo, and the hello element of bar are being targeted?
You can't with the current implementation. In order for this to work, you will have to create an array object (i.e.: an object that implements ArrayAccess). Something like:
class SuperArray implements ArrayAccess {
protected $_data = array();
protected $_parents = array();
public function __construct(array $data, array $parents = array()) {
$this->_parents = $parents;
foreach ($data as $key => $value) {
if (is_array($value)) {
$value = new SuperArray($value, array_merge($this->_parents, array($key)));
}
$this[$key] = $value;
}
}
public function offsetGet($offset) {
if (!empty($this->_parents)) echo "['".implode("']['", $this->_parents)."']";
echo "['$offset'] is being accessed\n";
return $this->_data[$offset];
}
public function offsetSet($offset, $value) {
if ($offset === '') $this->_data[] = $value;
else $this->_data[$offset] = $value;
}
public function offsetUnset($offset) {
unset($this->_data[$offset]);
}
public function offsetExists($offset) {
return isset($this->_data[$offset]);
}
}
class Test{
protected $foo;
public function __construct() {
$array['bar']['hello'] = 'world';
$this->foo = new SuperArray($array);
}
public function __get($name){
echo $name.' is being accessed.'.PHP_EOL;
return $this->$name;
}
}
$test = new Test;
echo $test->foo['bar']['hello'];
Should output:
foo is being accessed.
['bar'] is being accessed
['bar']['hello'] is being accessed
world
No you can't.
$myTest->foo['bar']['hello'] = 'world'; goes through the following translation
$myTest->__get('foo')['bar']['hello'] = 'world'; breaking them in parts become
$tmp = $myTest->__get('foo')
$tmp['bar']['hello'] = 'world';
What you can do is to create an ArrayAccess Derived Object. Where you define your own offsetSet() and return that from __get()
Instead of returning an array, you could return an object that implements ArrayAccess. Objects are always returned and passed by reference. This pushes the problem at least on level down.

Categories