intellix Posted June 13, 2011 Share Posted June 13, 2011 Hey, I'm having a little trouble with chaining and I can't quite understand why this is behaving like it is... it's probably obvious to anyone but myself getString() retrieves the string and returns the entire object (for chaining), show() will output it as a String (so that I can do other stuff to the string first) Here it is in it's basic form: $resources->getString("newsletter.hello")->show(); // returns "Hello Name" Then lets say I want to replace some text within that string... $resources->getString("newsletter.hello")->replace("name","Bob")->show(); // returns "Hello Bob" Now...... I want to replace some text within that string with another string I get using that object: $resources->getString("newsletter.hello")->replace("name", $resources->getString("admin.name")->show())->show(); // returns "Bob" (instead of "Hello Admin") Within the first call, it grabs "Hello name" but when it gets to the second call, it replaces "Hello name" with just "Bob" because it overrides the entire string with what the second call pulls back. I need to understand why the first item gets it's value replaced (I'm guessing its because its reusing the same object so the Variable gets replaced rather than maintaining it for when I need to replace something within it) but I'm not sure how to fix it. The class (stripped out crap so its easier to read): class resources{ private $currentLocale = "en"; private $string = ""; public function __construct($currentLocale){ $this->currentLocale = $currentLocale; } public function getString($stringName){ # Grabs stringName from an XML file $this->string = xmlfile($stringName); return $this; } function replace($replace_this, $with_this){ $this->string = preg_replace("/" . $replace_this . "/", $with_this, $this->string); return $this; } function show(){ return $this->string; } } I'd really appreciate the help, I'm looking to understand this issue... Quote Link to comment https://forums.phpfreaks.com/topic/239233-chaining-and-using-the-same-class/ Share on other sites More sharing options...
intellix Posted June 13, 2011 Author Share Posted June 13, 2011 I'm guessing that I need to create the opposite of a Singleton class... Like so: function getInstance(){ // If not created yet, create it and return if (self::$instance){ self::$instance = new resources(); } return self::$resources; } Will test and relay my results back here for future reference if it fixes or doesn't work Quote Link to comment https://forums.phpfreaks.com/topic/239233-chaining-and-using-the-same-class/#findComment-1229068 Share on other sites More sharing options...
intellix Posted June 13, 2011 Author Share Posted June 13, 2011 Nope... didn't work and I'm still stuck Quote Link to comment https://forums.phpfreaks.com/topic/239233-chaining-and-using-the-same-class/#findComment-1229090 Share on other sites More sharing options...
intellix Posted June 13, 2011 Author Share Posted June 13, 2011 What I'm trying to replicate is like something in Java... resources.getString("blahblah").replace("this","that").replace("that",resources.getString("anotherstring")); Each resources thing is contained as its own thing but you don't need to initiate each one of them so that its all chained and on one line and really clean. If anyone understands? Quote Link to comment https://forums.phpfreaks.com/topic/239233-chaining-and-using-the-same-class/#findComment-1229110 Share on other sites More sharing options...
ignace Posted June 13, 2011 Share Posted June 13, 2011 class Foo { private $_original = ''; private $_dirty = ''; public function getString() { $this->_original = 'whatever'; $this->_dirty = $this->_original; return $this; } public function show() { return $this->_dirty; } public function replace($thisstr, $thatstr) { $this->_dirty = str_replace($thisstr, $thatstr, $this->_original); return $this; } } #Use-Case 1 $resource->getString()->show(); // whatever $resource->getString()->replace('whatever', 'whichever')->show(); // whichever $resource->getString()->replace('whatever', 'what-eva')->show(); //what-eva Derived from: Here it is in it's basic form: $resources->getString("newsletter.hello")->show(); // returns "Hello Name" Then lets say I want to replace some text within that string... $resources->getString("newsletter.hello")->replace("name","Bob")->show(); // returns "Hello Bob" Now...... I want to replace some text within that string with another string I get using that object: $resources->getString("newsletter.hello")->replace("name", $resources->getString("admin.name")->show())->show(); // returns "Bob" (instead of "Hello Admin") Which is different from: resources.getString("blahblah").replace("this","that").replace("that",resources.getString("anotherstring")); class Foo { private $_string = ''; public function getString() { $this->_string = 'whatever'; return $this; } public function replace($thisstr, $thatstr) { $this->_string = str_replace($thisstr, $thatstr, $this->_string); return $this; } public function show() { return $this->_string; } } #Use-Case 2 $resources->getString()->show(); // whatever $resources->getString()->replace('whatever', 'whichever')->replace('whichever', 'what-eva')->show(); // what-eva Quote Link to comment https://forums.phpfreaks.com/topic/239233-chaining-and-using-the-same-class/#findComment-1229184 Share on other sites More sharing options...
ignace Posted June 13, 2011 Share Posted June 13, 2011 Now you realize where your thinking went wrong it's time to ponder further and question your current design. Since you could make this mistake someone else using your API will too. How to solve? This of course depends on how you want your design to behave. You could implement Lazy Initialization, since you suggested a Singleton I think this is the way you want to go without actually implemeting the Singleton of course. class Foo { private $_string; public function getString(){ if (is_null($this->_string)) { $this->_string = xmlfile(); } return $this; } } This has a drawback that once the value is loaded from the XML it's not "refreshed" on subsequent calls. $resources->getString()->show(); // bla $resources->getString()->replace('bla', 'foo')->show(); // foo $resources->getString()->show(); // foo In contrast to your current design where it loads bla from the XML on each call to getString() Quote Link to comment https://forums.phpfreaks.com/topic/239233-chaining-and-using-the-same-class/#findComment-1229193 Share on other sites More sharing options...
intellix Posted June 13, 2011 Author Share Posted June 13, 2011 Hi, thanks for the reply I've had a look through the code that you've posted and read into lazy initialisation and it sounds like what I'm trying to figure out. You process the string as many times as you need to and then at the end you display the item. I got a little closer to solving this at work but forgot to send it home to have another play so will try and mimic what I had created. I basically set it so that every call of getString created a new instance of the object so they were all unique but I had this problem... The first time it would allow a replace and would use its own object, but the next time I try it, it reused the first object like so: Object resources [1] Object resources [2] Object resources [1] The code you posted here works until you try and replace a string with something else from the XML file Heres the original: #Use-Case 2 $resources->getString()->show(); // whatever $resources->getString()->replace('whatever', 'whichever')->replace('whichever', 'what-eva')->show(); // what-eva And what doesn't seem to work when you try to replace using something else from the XML: #Use-Case 2 $resources->getString()->show(); // whatever $resources->getString()->replace('whatever', 'whichever')->replace('whichever', $resources->getString()->show())->show(); // should display "whatever" again The reason I wanted to chain was to make it really easy to replace strings one after the other: $string1.replace("blah","hello").replace("name","randomer").replace("what","is meant"); Otherwise you have loads of wrapping and it gets really ugly: str_replace("what","is meant", str_replace("name","randomer",str_replace("blah", "hello", $string1))); Quote Link to comment https://forums.phpfreaks.com/topic/239233-chaining-and-using-the-same-class/#findComment-1229257 Share on other sites More sharing options...
intellix Posted June 13, 2011 Author Share Posted June 13, 2011 class resources{ private static $instance, $string; public static function getString($stringName){ # Create new instance self::$instance = new self; # Grabs stringName from an XML file self::$string = $stringName; # Return instance var_dump(self::$instance); return self::$instance; } public static function replace($replace_this, $with_this){ # Replace and return instance self::$string = str_replace($replace_this, $with_this, self::$string); return self::$instance; } public static function show(){ # Return String return self::$string; } } echo resources::getString("alpha") // alpha ->replace("lpha","bravo") // abravo ->replace("vo", resources::getString("charlie")->show()) // should be abracharlie ->show(); // charlie This is the closest I thought I had got... but the original value gets replaced with 'charlie' instead of maintaining 'abravo' and replacing part of that... So close yet so far away! Quote Link to comment https://forums.phpfreaks.com/topic/239233-chaining-and-using-the-same-class/#findComment-1229264 Share on other sites More sharing options...
intellix Posted June 13, 2011 Author Share Posted June 13, 2011 Managed to get this solved I originally came across a solution using a static object and another method but was given a much better solution by a guy named Ryano from Stackoverflow... I will post his solution (I won't include mine as I don't want others to use bad code) class resources { private $string; public function __construct ($string) { $this->string = $string; } public static function getString ($string) { $obj = new resources($string); return $obj; } public function replace ($replace_this, $with_this) { # Replace and return instance $this->string = str_replace($replace_this, $with_this, $this->string); return $this; } public function show () { # Return String return $this->string; } } Quote Link to comment https://forums.phpfreaks.com/topic/239233-chaining-and-using-the-same-class/#findComment-1229327 Share on other sites More sharing options...
ignace Posted June 14, 2011 Share Posted June 14, 2011 $resources->getString()->replace('whatever', 'whichever')->replace('whichever', $resources->getString()->show())->show(); // should display "whatever" again No, that should display whichever anything else is wrong due to the lazy initalization as you are actually doing this: $resources->getString()->replace('whatever', 'whichever')->replace('whichever', 'whichever')->show(); // should display "whatever" again You see str_replace("what","is meant", str_replace("name","randomer",str_replace("blah", "hello", $string1))); This is also not true since str_replace accepts an array. Very few people seem to know this feature exists. str_replace(array("what", "name", "blah"), array("is meant","randomer", "hello"), $string1); echo resources::getString("alpha") // alpha ->replace("lpha","bravo") // abravo ->replace("vo", resources::getString("charlie")->show()) // should be abracharlie ->show(); // charlie This doesn't work because when you replace "vo" you set the static value of $string to "charlie" effectively trying to replace "vo" in "charlie". Quote Link to comment https://forums.phpfreaks.com/topic/239233-chaining-and-using-the-same-class/#findComment-1229422 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.