jamiecarter Posted September 25, 2015 Share Posted September 25, 2015 Guys, total PHP noob here but years of MS development experience (I know, I know,,,). Really need to get an understanding of this code, I have a handle on the individual lines and can run the code, but overall I'm kinda at a loss, all help much appreciated! class MyTestClass { const REGEXP = '/\{(((?>[^\{\}]+)|(?R))*)\}/x'; public function render($text) { return preg_replace_callback( self::REGEXP, [$this, 'replace'], $text ); } public function replace($text) { $text = $this->render($text[1]); $parts = explode('|', $text); return trim($parts[array_rand($parts)]); } } $obj = new MyTestClass(); $result = $obj->replace("Fred"); echo $result; Quote Link to comment https://forums.phpfreaks.com/topic/298311-help/ Share on other sites More sharing options...
scootstah Posted September 25, 2015 Share Posted September 25, 2015 What exactly are you struggling with? Quote Link to comment https://forums.phpfreaks.com/topic/298311-help/#findComment-1521540 Share on other sites More sharing options...
hansford Posted September 25, 2015 Share Posted September 25, 2015 That regex is not going to work. Lay out in detail what you expect this class to do. Quote Link to comment https://forums.phpfreaks.com/topic/298311-help/#findComment-1521542 Share on other sites More sharing options...
Jacques1 Posted September 26, 2015 Share Posted September 26, 2015 (edited) The regex is perfectly fine, but you're not using the class correctly. What this does is look for substrings of the kind {<choice1>|<choice2>|<choice3>|...|<choicen>} and randomly replace them with one of the substrings <choice1>, <choice2>, <choice3>, ..., <choicen>. For example, Have a look at our {fabulous|fantastic|awesome} pet shop. could become “Have a look at our fantastic pet shop.” or “Have a look at our awesome pet shop”. Nested patterns are also supported: We sell {furry {cats|kittens}|adorable dogs}. So it's basically a simple text generator. You use the class by calling the render() method with an appropriate input. Do not call replace(), that's just an internal method. <?php class TextGenerator { const REGEXP = '/\{(((?>[^{}]+)|(?R))*)\}/'; public function render($text) { return preg_replace_callback( self::REGEXP, [$this, 'replace'], $text ); } public function replace($text) { $text = $this->render($text[1]); $parts = explode('|', $text); return trim($parts[array_rand($parts)]); } } $textGenerator = new TextGenerator(); echo $textGenerator->render('We sell {furry {cats|kittens}|adorable dogs}.'); Edited September 26, 2015 by Jacques1 Quote Link to comment https://forums.phpfreaks.com/topic/298311-help/#findComment-1521550 Share on other sites More sharing options...
jamiecarter Posted September 26, 2015 Author Share Posted September 26, 2015 Jacques1 - thank you very much for the reply - it has really helped. In the Replace function, the line $text = $this->render($text[1]); is confusing me, does this "recall" the Render function?? If I had to add a second parameter to Render, how would I pass it into the callback? Thanks Quote Link to comment https://forums.phpfreaks.com/topic/298311-help/#findComment-1521563 Share on other sites More sharing options...
Jacques1 Posted September 27, 2015 Share Posted September 27, 2015 In the Replace function, the line $text = $this->render($text[1]); is confusing me, does this "recall" the Render function?? Yes, the method is called repeatedly to handle nested expressions. If I had to add a second parameter to Render, how would I pass it into the callback? You can use a closure as the callback function. It has access to variables in the scope of its definition: <?php class TextGenerator { const REGEXP = '/\{(((?>[^{}]+)|(?R))*)\}/'; public function render($text, $separator) { $replace = function ($subject) use ($separator) { $subject = $this->render($subject[1], $separator); $parts = explode($separator, $subject); return trim($parts[array_rand($parts)]); }; return preg_replace_callback( self::REGEXP, $replace, $text ); } } $textGenerator = new TextGenerator(); $separator = '/'; echo $textGenerator->render('We sell {furry {cats/kittens}/adorable dogs}.', $separator); This is actually a cleaner solution in general, because you don't need a pseudo-public replace() method. Quote Link to comment https://forums.phpfreaks.com/topic/298311-help/#findComment-1521583 Share on other sites More sharing options...
jamiecarter Posted September 27, 2015 Author Share Posted September 27, 2015 Wow. Great much appreciated! Quote Link to comment https://forums.phpfreaks.com/topic/298311-help/#findComment-1521653 Share on other sites More sharing options...
jamiecarter Posted September 27, 2015 Author Share Posted September 27, 2015 One final question - promise! Why will the above code not work in PHP 5.3, its fine in 5.4 and above? Thanks Quote Link to comment https://forums.phpfreaks.com/topic/298311-help/#findComment-1521657 Share on other sites More sharing options...
Jacques1 Posted September 28, 2015 Share Posted September 28, 2015 PHP 5.3 doesn't support $this in a closure. You need to explicitly import it as a variable: public function render($text, $separator) { $currentObject = $this; $replace = function ($subject) use ($currentObject, $separator) { $subject = $currentObject->render($subject[1], $separator); ... }; } Note that both PHP 5.3 and PHP 5.4 have reached end-of-life. Quote Link to comment https://forums.phpfreaks.com/topic/298311-help/#findComment-1521663 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.