With an object like this:
class test {
var $propa = 'a';
var $propb = 'b';
var $propc = 'c';
var $propd = array(1,2,3,4);
}
How do I iterate with test::$propd using foreach WITHOUT direct reference? eq:
$t = new test;
foreach ($t as $k => $v){
echo 'propd['.$k.']='.$v.', ';
}
// propd[0]=1, propd[1]=2, propd[2]=3, ...
Is there some stuff involving implement ArrayAccess?
Thx!
I would recommend separating functionality, and setting your properties as private.
Example:
class Test {
private $propertyA = 'a';
private $propertyB = 'b';
public function getProperties()
{
return [
'propertyA' => $this->propertyA,
'propertyB' => $this->propertyB
];
}
}
However, if the property values are to change then do getters and setters for the properties.
With the above code you can do:
<?php
$test = new Test;
foreach ($test->getProperties() as $key => $value) {
echo $key . ' = ' . $value;
}
?>
You can also limit what properties you want to output with this method.
Related
This is my code:
class A {
public static $a = '1';
}
class B extends A {
public static $b = '2';
}
$refclass = new ReflectionClass('B');
foreach ($refclass->getStaticProperties() as $key => $property)
echo $key;
This code prints $a and $b.
Is there any way to get the class properties without getting the inherited parents class properties.
foreach ($refclass->getStaticProperties() as $key => $property)
if ($refclass->getProperty($key)->getDeclaringClass() == $refclass) {
echo $key;
}
}
Or, perhaps more elegant:
$props = array_filter($refclass->getProperties(ReflectionProperty::IS_STATIC), function ($prop) use ($refclass) {
return $prop->getDeclaringClass() == $refclass;
});
I have class with 100 public members. How can I update them in an automated way, ie without specifying their name. I have tried this and I'm getting variables but the changes made doesn't reflect on actual object. Please advice.
class foo {
public $b = 1;
public $c = 2;
function __construct()
{
$x = get_object_vars($this);
foreach ($x as $obj) {
$obj = 9;
}
}
}
$test = new foo;
echo $test->c;
It prints vale of 'c' as 2 instead of 9
function __construct()
{
$x = get_object_vars($this);
foreach ($x as $key => $value) {
$this->$key = 9;
}
}
If i use magic __set to set a value to private var how could i set a var as an array ?
Im thinking of something like this, pretend i have a class with __get __set
$myclass->names = 'Name'; // Works
$myclass->names = array('n1'=>'Name1', 'n2' => 'Name2'); // works as well
//this does not work
$myclass->names['n1'] = 'Name1';
$myclass->names['n2'] = 'Name2';
Its the 2 last examples i want to get to work. Have tested various ways but cant figure it out.
You obviously don't output notices, otherwise you'd have gotten the error
Notice: Indirect modification of overloaded property Foo::$bar has no
effect
What you're trying to do is simply not possible. There is exactly one way to make arrays received through __get writable, but that is most likely not what you want.
<?php
class Foo {
protected $bar = array();
public function &__get($name) {
return $this->$name;
}
public function __set($name, $value) {
return $this->$name = $value;
}
}
$foo = new Foo();
$foo->bar = array('a', 'b', 'c');
echo $foo->bar[0]; // output "a"
$foo->bar[0] = 'z'; // fires warning
echo $foo->bar[0]; // output "z"
// all fine, but here's the catch:
$t =& $foo->bar;
$t = array('y');
echo $foo->bar[0]; // output "y"
Now that you've seen how returning values by reference can be a problem, you may be interested in ArrayObject. Something like
<?php
class Foo {
protected $bar = array();
public function __get($name) {
return new ArrayObject(&$this->$name);
}
public function __set($name, $value) {
return $this->$name = $value;
}
}
$foo = new Foo();
$foo->bar = array('a', 'b', 'c');
echo $foo->bar[0]; // output "a"
$foo->bar[0] = 'z'; // fires warning
echo $foo->bar[0]; // output "z"
// all fine, and no catch
$t =& $foo->bar;
$t = array('y');
echo $foo->bar[0]; // still outputs "z"
It won't work. $class->arr['key'] will execute the getter. So basically, what your code will look like is:
array('key' => 'value')['key'] = 'new value';
Which, obviously, does nothing. If you want that to work, you will have to declare the names as a public property.
This expression will invoke the getter:
$myclass->names['n1'] = 'Name1';
^^^^^^^^^^^^^^^
needs to be get
^^^^^^^^^^^^^^^^
assignment later
The only way to make that work is a fugly workaround. By letting the getter return an reference to the know array the following assignment could work.
function & __get($name) {
if (is_array($this->$name)) {
return & $this->$name;
}
else ...
}
So it's really only advisable if it significantly simplifies your API.
Try this code:
class Foo
{
private $bar;
public function __construct()
{
$this->bar = new ArrayObject(array());
}
public function __get($item)
{
if(property_exists($this, $item)) {
return $this->$item;
}
}
public function __set($item, $value)
{
if(property_exists($this, $item)) {
$this->{$item} = $value;
}
}
}
$obj = new Foo();
$obj->bar['color'] = 'green';
foreach($obj->bar as $attribute => $value) {
echo '<p>' . $attribute . ' : ' . $value . '</p>' . PHP_EOL;
}
// output => color : green
What I'm trying to do is use a temporary object to store values and then reset it back to empty without having to uset($tmpObject); ?
Here is some example code:
class Object {
function ResetObject(){
// code to remove all variables in an object here?
}
}
$tmpObject = new Object();
foreach ($myArray as $arr){
$tmpObject->val1 = "string1";
$tmpObject->val2 = "string2";
$tmpObject->val3 = "string3";
$tmpObject->val4 = "string4";
$template->set('tmpObject',$tmpObject);
$tmpObject->ResetObject();
}
Anyone have any ideas?
class Object {
function ResetObject() {
foreach ($this as $key => $value) {
unset($this->$key);
}
}
}
See: Object iteration
The accepted answer has a minor flaw which is that unsetting a property actually completely removes it from that object, so that a check like $this->someProperty == null would trigger an "Undefined property" notice. Properties are null by default, so this would be more correct:
class Object {
function resetObject() {
foreach ($this as $key => $value) {
$this->$key = null; //set to null instead of unsetting
}
}
}
There's also the possibility that some of the properties could have been given default values (e.g. protected $someArray = array();)...if you want to reset all the properties back to their original default values then you have to use reflection:
class Object {
function resetObject() {
$blankInstance = new static; //requires PHP 5.3+ for older versions you could do $blankInstance = new get_class($this);
$reflBlankInstance = new \ReflectionClass($blankInstance);
foreach ($reflBlankInstance->getProperties() as $prop) {
$prop->setAccessible(true);
$this->{$prop->name} = $prop->getValue($blankInstance);
}
}
}
That may be overkill but could be important in some scenarios. Note that this would fail if the class had required constructor arguments; in that case you could use ReflectionClass::newInstanceWithoutConstructor (introduced in PHP 5.4), then call __construct() manually after calling resetObject().
If your class has a constructor method which initialises everything, then you could just call that again to reset.
<?php
function reset() {
foreach (get_class_vars(get_class($this)) as $var => $def_val){
$this->$var= $def_val;
}
}
?>
Instead of unset and even setting null, setting to default may be a better idea
class Foo {
public $bar = 'default bar';
private $baz = 'something';
function __construct ()
{
/* assign whatever */
}
public function resetMe():Foo
{
$instance = new Foo();
foreach($instance as $k => $v)
$this->{$k} = $v;
}
return $this;
}
To use this
$foo = new Foo();
$foo->bar = 'set something different';
echo $foo->bar; // 'set something different'
$foo->resetMe();
echo $foo->bar; // 'default bar'
Reinitializing the variable will restore all object members to their preset values.
<?php
class Object {
public $val1 = "val1";
public $val2 = "val2";
}
$tmpObject = new Object();
$tmpObject->val1 = "string1";
$tmpObject->val2 = "string2";
$tmpObject->val3 = "string3";
$tmpObject->val4 = "string4";
var_dump($tmpObject);
$tmpObject = new Object();
var_dump($tmpObject);
?>
Outputs:
object(Object)#1 (4) {
["val1"]=>
string(7) "string1"
["val2"]=>
string(7) "string2"
["val3"]=>
string(7) "string3"
["val4"]=>
string(7) "string4"
}
object(Object)#2 (2) {
["val1"]=>
string(4) "val1"
["val2"]=>
string(4) "val2"
}
Another way which combine unset and set with default value.
class Object {
public function resetObject()
{
$clean = new self;
foreach ($this as $key => $val){
// If the attribute have a default value, use it
if (isset($clean->$key)){
$this->$key = $clean->$key;
}else{
unset($this->$key);
}
}
}
}
You can do this with reflection:
private function resetPropertiesToDefault()
{
$blankInstance = $this->newInstance();
$reflBlankInstance = new \ReflectionClass($blankInstance);
foreach ($reflBlankInstance->getProperties() as $prop) {
if ($prop->isStatic()) {
continue;
}
$prop->setAccessible(true);
$this->{$prop->name} = $prop->getValue($blankInstance);
}
}
I'm taking array output from a command-line program and parsing it into a PHP object. Consider this example of a very simple way to do this:
$output = explode("\n", shell_exec(myProg));
$obj = new MyObject();
$offset_field1 = 0;
$offset_field2 = 1;
$obj->Field1 = $output[$offset_field1];
$obj->Field2 = $output[$offset_field2];
This is a bit cumbersome, especially when the number of fields increases. Is there a better design pattern or method to accomplish the same feat in a less heavy-handed manner?
Why not put the assignment code in the object?
class MyObject
{
public function __construct(array $data)
{
$this->Field1 = $data['keyname1'];
$this->Field2 = $data['keyname2'];
...
}
}
or use the get magic method.
class MyObject
{
protected $data;
public function __construct(array $data)
{
$this->data = $data;
}
public function __get($key)
{
$map = array('Field1' => 1, 'Feild2' => 2, ...);
if (isset($map[$key])) {
return $this->data[$map[$key]];
}
}
}
I guess this should work:
$output = explode("\n", shell_exec(myProg));
$obj = new MyObject();
foreach ($output as $key => $value)
{
$obj->{'Field' . ($key + 1)} = $value;
}
As it seems you cannot guess the field name from the outpout of your programm, you will have to define it somewhere.
$key_map = array('field_name1', 'field_name2', 'etc');
$obj = new MyObject();
foreach(explode("\n", shell_exec(myProg)) as $k => $v)
{
if(isset($key_map($k))
$obj->$key_map[$k] = $v;
}