PHP Chaining... I just can't get it!
I'm trying to create a chaining function for working with strings that are returned from an XML file.
1 original string may have multiple replacements, some of which come from the XML file.
Here is the ugly and standard wrapped approach:
str_replace("what","is meant", str_replace("name","randomer",str_replace("blah", "hello", $string1)));
Here is the approach I'm trying to replicate (like Java):
$string1.replace("blah","hello").replace("name","randomer").replace("what","is meant");
With the above, it works easily... until I use the XML function to get the replacing string.
Here's my class:
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
I'd like it to understand why it's not working as I think it should and how it should actually work. It seems that when I call the class again (despite var_dump saying its a seperate instance), it replaces the original text with "charlie" so I can't just replace a part of the first bit.
Thanks, Dominic
EDIT: Yes!! I have figured it out (using statics) but it seems Ryano below has an even better solution
<?php
class resources{
private static $instance, $string, $originalString;
public static function getInstance($stringName){
self::$instance = new self();
self::$originalString = $stringName;
return self::$instance;
}
public static function getString($stringName){
# Grabs stringName from an XML file
self::$string = $stringName;
return self::$instance;
}
functi开发者_开发技巧on replace($replace_this, $with_this){
self::$originalString = str_replace($replace_this, $with_this, self::$originalString);
self::$string = self::$originalString;
return self::$instance;
}
function show(){
return self::$string;
}
}
echo resources::getInstance("alpha") // alpha
->replace("lpha","bravo") // abravo
->replace("vo", resources::getString("charlie")->show()) // should be abracharlie
->replace("lie", resources::getString("vo")->show()) // abracharvo
->show(); // abracharvo
echo "<br />";
echo resources::getInstance("randomer") // randomer
->replace("er","") // random
->replace("ran", resources::getString("")->show()) // dom
->replace("dom", resources::getString("Dom")->show()) // Dom
->show(); // Dom
echo "<br />";
echo resources::getInstance("nomster") // nomster
->replace("nom","nmo") // nmoster
->replace("nom", resources::getString("mon")->show()) // nmoster
->replace("nmo", resources::getString("mon")->show()) // monster
->show(); // monster
?>
Your problem is that everything is static. I would suggest brushing up on some object-oriented programming fundamentals.
Because everything is static, the state is shared between all invocations of the functions. In the line replace("vo", resources::getString("charlie")->show())
, the nested call to resources::getString
replaces the string built so far (abravo
) with the argument to getString
which is charlie
. Then the wrapping function is called like replace("vo", "charlie")
, but the value of self::$string
is now charlie
, which does not contain vo
and therefore the final show()
then returns simply charlie
. If, instead of vo
, you'd called it with replace("ar", resources::getString("charlie")->show())
, the final show()
would have instead returned chcharlielie
.
You must create a class with non-static member variables and methods in order to maintain separate states.
Here's a working version:
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;
}
}
Edit: I like the above code as the closest transition from the question's code. If I was writing something similar myself, I would simplify it further like this:
class Str {
private $str;
private function __construct ($str) {
$this->str = $str;
}
public static function with ($str) {
return new Str($str);
}
public function replace($replace_this, $with_this) {
$this->str = str_replace($replace_this, $with_this, $this->str);
return $this;
}
public function __toString () {
return $this->str;
}
}
echo Str::with('nomster')->replace('nom', 'mon') . "\n";
Now there's no need for show()
and the names are a little nicer to type. Many other useful methods could be added here; any php string function you would want to chain.
When you call getString()
several times, you create several instances since you call new self()
in getString()
.
To prevent that from happening you should create a method getInstance()
and use that in getString()
public static function getInstance() {
if(!self::instance) {
self::instance = new self();
}
return self::instance;
}
public static function getString() {
$instance = self::getInstance();
// use $instance here instead of self::instance
}
精彩评论