silkfire Posted September 28, 2012 Share Posted September 28, 2012 I have a pretty large project now that uses quite a couple of classes. Now I've stumbled upon this problem. I have a class with properties that are public. Objects of this class are inserted into a container (which is another class). I have made so that if any of the properties are set to false (in the __set function), then the value must be reverted to the default value. The default value is taken from an object that is created in the construct (object of oneself witjin object). I think this causes an infinite recursion. What's the best way to solve this problem? This container may contain like 10 objects of my class, each of these in turn - an object with default values that is same for all. It seems unnecessary to create this object in every object. I know this sounds a bit confusing but don't know how to solve this. Also, if the container class is the one to have the default values then the object class needs to have access to it somehow, but even if that would be possible then each object would be really huge because it also contains the container?? class SmallObject() { private $default_object; function __construct() { $this->color = '#5432FA'; $this->size = 5.3; $this->default_object = new SmallObject(); } function __set($property, $value) { if ($value === false) $this->$property = $this->default_object->$property; } } Quote Link to comment https://forums.phpfreaks.com/topic/268874-creating-default-object-within-object/ Share on other sites More sharing options...
trq Posted September 28, 2012 Share Posted September 28, 2012 You've lost me. Quote Link to comment https://forums.phpfreaks.com/topic/268874-creating-default-object-within-object/#findComment-1381498 Share on other sites More sharing options...
silkfire Posted September 28, 2012 Author Share Posted September 28, 2012 Yeah it's not very clear, but which part do you want me to explain better? Quote Link to comment https://forums.phpfreaks.com/topic/268874-creating-default-object-within-object/#findComment-1381499 Share on other sites More sharing options...
ignace Posted September 28, 2012 Share Posted September 28, 2012 (edited) The default value is taken from an object that is created in the construct (object of oneself witjin object).I think this causes an infinite recursion. What's the best way to solve this problem? Obviously by not creating the object inside the constructor... class SmallObject { private $default_object; protected function getInner() { if ($this->default_object === null) { $this->default_object = new static(); } return $this->default_object; } public function __set($key, $val) { if ($val === false) { $val = $this->getInner(); } $this->{$key} = $val; } } This container may contain like 10 objects of my class, each of these in turn - an object with default values that is same for all. It seems unnecessary to create this object in every object. It does. Simply make it static. Static means it is shared across all instances. class SmallObject { private static $default_object; protected function getInner() { if (static::$default_object === null) { static::$default_object = new static(); } return static::$default_object; } public function __set($key, $val) { if ($val === false) { $val = $this->getInner(); } $this->{$key} = $val; } } Also, if the container class is the one to have the default values then the object class needs to have access to it somehow, but even if that would be possible then each object would be really huge because it also contains the container?? Get out of that mindset of thinking that your consuming too much memory and that you should limit the number of objects you create. Pre-mature optimization is evil! First make it work, then make it work fast! Edited September 28, 2012 by ignace Quote Link to comment https://forums.phpfreaks.com/topic/268874-creating-default-object-within-object/#findComment-1381501 Share on other sites More sharing options...
JonnoTheDev Posted September 28, 2012 Share Posted September 28, 2012 (edited) Your use of objects is wrong. Member variables can contain default values simply by setting them when the are declared. A class should not hold an instance of itself unless you are using the SIngleton pattern. This is where you would not want the object to accidentally be redeclared and its values reset i.e a database object. A second object can hold instances of the first object and use its methods. See below <?php // a simple class class foo { public $color = '#5432FA'; public $size = '5.3'; public function __construct($color = FALSE, $size = FALSE) { if($color) { $this->color = $color; } if($size) { $this->size = $size; } } public function get_color() { return $this->color; } public function get_size() { return $this->size; } } // another simple class that contains foo objects class bar { protected $foos = array(); public function add_foo(foo $foo) { $this->foos[] = $foo; } public function display_foo_data() { foreach($this->foos as $foo) { print "<p>Color: ".$foo->get_color().", Size: ".$foo->get_size()."</p>"; } } } // usage $a = new foo(); $b = new foo('#FFFFFF', 10); $c = new foo(); $bar = new bar(); $bar->add_foo($a); $bar->add_foo($B); $bar->add_foo($c); $bar->display_foo_data(); ?> Edited September 28, 2012 by neil.johnson Quote Link to comment https://forums.phpfreaks.com/topic/268874-creating-default-object-within-object/#findComment-1381502 Share on other sites More sharing options...
silkfire Posted September 28, 2012 Author Share Posted September 28, 2012 (edited) Thanks for the help, ignace. I've got some questions though. 1. I had no idea you could use the keyword static as in static:: (I mean, it's not a class?) or static() (it's not a function?). What do these mean? 2. Where in your solution do I give the properties of default_object its default values? Remember that the values of default_object must be the initial values of my SmallObject upon construction. 3. By the way, I use this object so that new objects can inherit properties from an existing object. If I want to set some property to its default value I do like this: $object3->size = false; 4. Why is default_object access type protected? Can it be private? 5. In the __set function, if I forget $this->{$key} = $val;, will the value never be set, i.e. will it override/prevent default behavior? Edited September 28, 2012 by silkfire Quote Link to comment https://forums.phpfreaks.com/topic/268874-creating-default-object-within-object/#findComment-1381514 Share on other sites More sharing options...
ignace Posted September 28, 2012 Share Posted September 28, 2012 (edited) 1. I had no idea you could use the keyword static as in static:: (I mean, it's not a class?) or static() (it's not a function?). What do these mean? See http://php.net/manual/en/language.oop5.late-static-bindings.php 4. Why is default_object access type protected? Can it be private? It already is. Like Neil already mentioned you are possibly going about this all wrong. By the way, I use this object so that new objects can inherit properties from an existing object. You can simply clone an existing object. $prototype = new SmallObject(); // contains all defaults $newSmallObject = clone $prototype; $newerSmallObject = clone $prototype; If I want to set some property to its default value I do like this: $object3->size = false; Something that also may work is: class SmallObject { private $data; private $defaults; public function __construct() { //setup data and defaults $this->color = 'foo'; $this->size = 'bar'; } public function __set($key, $val) { if ($val === false) { $val = $this->defaults[$key] ?: null; } if (!isset($this->defaults[$key])) { $this->defaults[$key] = $val; } $this->data[$key] = $val; } public function __get($key) { return $this->data[$key]; } } $smallObject = new SmallObject(); $smallObject->color = 'bat'; echo $smallObject->color, PHP_EOL; // bat $smallObject->color = false; echo $smallObject->color, PHP_EOL; // foo Not sure either of these are an ideal solution for you either. Can you explain why you have opted to do it like this? Why do you need to be able to set them back to their default? Edited September 28, 2012 by ignace Quote Link to comment https://forums.phpfreaks.com/topic/268874-creating-default-object-within-object/#findComment-1381522 Share on other sites More sharing options...
silkfire Posted September 28, 2012 Author Share Posted September 28, 2012 Thanks again. This line right here doesn't make sense to me: $val = $this->defaults[$key] ?: null; Will it be null either way? Well I can't explain what exactly I'm working with but I want the object creation to use as few steps as possible. When I create an object with properties and want to create a new one but with different color and not copy its size, I want the class to automatically take care of this for me. $a = new SmallObject(); $a->color = 'red'; $a->size = 32; $a->shared = true; $a->url = 'www.example.com'; $a->country = 'DE'; ... // 6-10 more properties Instead of assigning all those properties again if I want to change country and use default color I do: $b = clone $a; $a->color = false; // Set to default value $a->country = 'US'; Or am I making this harder than it should be? Quote Link to comment https://forums.phpfreaks.com/topic/268874-creating-default-object-within-object/#findComment-1381540 Share on other sites More sharing options...
silkfire Posted September 28, 2012 Author Share Posted September 28, 2012 See it a bit like bitwise operations. I maybe want to copy some bits (properties, bitwise-OR), but reset others to default (negation + AND). Quote Link to comment https://forums.phpfreaks.com/topic/268874-creating-default-object-within-object/#findComment-1381541 Share on other sites More sharing options...
Mahngiel Posted September 28, 2012 Share Posted September 28, 2012 isnt this what getters and setters are for? so you can edit an existing object, cloned or not? im on mobile so no test code for u. Quote Link to comment https://forums.phpfreaks.com/topic/268874-creating-default-object-within-object/#findComment-1381549 Share on other sites More sharing options...
ignace Posted September 29, 2012 Share Posted September 29, 2012 $val = $this->defaults[$key] ?: null; Means that $val === null when $this->defaults[$key] evaluates to false, it's the value of $this->defaults[$key] otherwise. When I create an object with properties and want to create a new one but with different color and not copy its size, I want the class to automatically take care of this for me. You can use a Factory for that but then that only works at object creation time, so afterwards setting a value to false, means it will be false. You can use a Prototype, create an object that holds all the default values and use the clone keyword to create new objects from these defaults. But neither of these make sure that when you set a given property to false (what with boolean properties?) it will get set back to the default value. To do this you need to do something like: class SmallObject { private $data = array(); private static $defaults = array( 'color' => '..', 'size' => '..', ); public function __construct($data = array()) { $this->data = array_merge(self::$defaults, $data); } public function __set($key, $val) { if ($val === false) { $val = self::$defaults[$key]; } $this->data[$key] = $val; } public function __get($key) { return $this->data[$key]; } } Every new object will have these defaults set: $o1 = new SmallObject(); echo $o1->color, PHP_EOL; // .. $o1->color = 'bar'; echo $o1->color, PHP_EOL; // bar $o1->color = false; echo $o1->color, PHP_EOL; // .. $o2 = new SmallObject(array('color' => 'foo')); echo $o2->color, PHP_EOL; // foo Quote Link to comment https://forums.phpfreaks.com/topic/268874-creating-default-object-within-object/#findComment-1381713 Share on other sites More sharing options...
silkfire Posted September 30, 2012 Author Share Posted September 30, 2012 Just a quick question. Why is $defaults static? Does it mean it will only be created once during script execution? I mean it's private too so it's not going to be accessed outside the class either. Quote Link to comment https://forums.phpfreaks.com/topic/268874-creating-default-object-within-object/#findComment-1381962 Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.