Hello and welcome to our community! Is this your first visit?
Register
Enjoy an ad free experience by logging in. Not a member yet? Register.
Results 1 to 12 of 12
  1. #1
    Regular Coder
    Join Date
    Apr 2003
    Location
    Montreal, QC
    Posts
    340
    Thanks
    3
    Thanked 2 Times in 2 Posts

    Variables within Strings within Variables?

    This is kind of weird. Here's what I'm trying to so:

    I have a variable that contains a string with a variable in it, and I want the variable in the string to be properly replaced. Here's some example code:

    PHP Code:
    $greeting = array('gr'=>"Hi there $myname[1],");

    $myname = array('John','Frank');

    echo 
    $greeting['gr'];
    // should output "Hi there Frank," 
    Now, I know if I reverse lines 1 and 3, it will work, but because of the way my application is written that can't happen, (I'm making a website multilingual, so I get the phrases first, (like "Hi here $myname[1]"), and then do most of the other logic later.

    Is there a way to reprocess the string stored in $greeting['gr'] so that the variables are replaced?
    Search for Laughter or Just Search?
    GiggleSearch.org
    Blog: www.johnbeales.com
    All About Ballet: www.the-ballet.com

  • #2
    UE Antagonizer Fumigator's Avatar
    Join Date
    Dec 2005
    Location
    Utah, USA, Northwestern hemisphere, Earth, Solar System, Milky Way Galaxy, Alpha Quadrant
    Posts
    7,691
    Thanks
    42
    Thanked 637 Times in 625 Posts
    How about using a placeholder string that you won't find in normal text, such as "__##__", then using str_replace on the array element when you echo?

    PHP Code:
    $greeting = array('gr'=>"Hi there __##__,");

    $myname = array('John','Frank');

    echo 
    str_replace("__##__"$myname[1], $greeting['gr']); 

  • #3
    Regular Coder
    Join Date
    Apr 2003
    Location
    Montreal, QC
    Posts
    340
    Thanks
    3
    Thanked 2 Times in 2 Posts
    The problem is that there are more than 100 different variables that could appear in the greeting array... and to do a str_replace on them all would be a pretty big, and slow, function.
    Search for Laughter or Just Search?
    GiggleSearch.org
    Blog: www.johnbeales.com
    All About Ballet: www.the-ballet.com

  • #4
    Senior Coder
    Join Date
    Jan 2007
    Posts
    1,648
    Thanks
    1
    Thanked 58 Times in 54 Posts
    That's why you use a regular expression.

  • #5
    UE Antagonizer Fumigator's Avatar
    Join Date
    Dec 2005
    Location
    Utah, USA, Northwestern hemisphere, Earth, Solar System, Milky Way Galaxy, Alpha Quadrant
    Posts
    7,691
    Thanks
    42
    Thanked 637 Times in 625 Posts
    How ironic, since str_replace is faster than regex's, and I can't visualize how regex would be any cleaner-- wouldn't you have to run 100 regex's?

    JohnnyB you can send arrays to str_replace() so you only have to call the function once-- I doubt you'd see any kind of performance hit.

  • #6
    Regular Coder
    Join Date
    Apr 2003
    Location
    Montreal, QC
    Posts
    340
    Thanks
    3
    Thanked 2 Times in 2 Posts
    So it looks like I have 2 options so far:
    1) str_replace with a huge array of needles, (and maybe replaces as well)
    2) a regex that would probably find a pattern something like ${(variablename)}, then capture the variable name and somehow grab the variable from the surrounding code then replace it in the string, (would probably require a pass by preg_match then a second by preg_replace, maybe the _all variants depending on how tricky I get).

    Ideally, I'd like to avoid searching through strings alltogether though. Since if I define $myname before I define $greeting everything works properly, it seems like there should be a way to convince PHP that the contents of $greeting are a literal, instead of a string from before, therefore by assigning the faux-literal to a variable, I should have a completed string. I realize that this is probably a rare request, but I can see it being really useful at times. If you have any more insight that would be great.
    Search for Laughter or Just Search?
    GiggleSearch.org
    Blog: www.johnbeales.com
    All About Ballet: www.the-ballet.com

  • #7
    Regular Coder
    Join Date
    Apr 2003
    Location
    Montreal, QC
    Posts
    340
    Thanks
    3
    Thanked 2 Times in 2 Posts

    Solution! With a caveat.

    So, I have a solution:
    PHP Code:
    error_reporting(E_ALL);
    ini_set("display_errors","on");


    function 
    process($k) {
        global 
    $myname,$greeting;
        
        
    $t $greeting[$k];
        
    $greeting[$k] = $t;
        echo 
    $t.'<br/>';
        eval(
    '$str = "'.addslashes($t).'";');
        
        return 
    $str;
        
    }


    $greeting = array('gr'=>'Hi there "{$myname[1]},"');

    $myname = array('John','Frank');

    echo 
    process('gr');
    // should output "Hi there Frank," 
    However, it uses eval(). I'm going to see if there's a way to get around this, perhaps some sort of stripped-down eval? I haven't dived into the eval() manual yet, I will post back when I have.
    Search for Laughter or Just Search?
    GiggleSearch.org
    Blog: www.johnbeales.com
    All About Ballet: www.the-ballet.com

  • #8
    Senior Coder
    Join Date
    Jan 2007
    Posts
    1,648
    Thanks
    1
    Thanked 58 Times in 54 Posts
    How ironic, since str_replace is faster than regex's, and I can't visualize how regex would be any cleaner-- wouldn't you have to run 100 regex's?
    No, you wouldn't.

    You can use preg_replace_callback() to call upon a function for each replacement, which grabs the data from a specific source. So you define a pattern for your variables (such as {VARIABLENAME}), create the regex to collect each occurence.

    Code:
    #\{([^\}]+)\}#
    Then create a function which either has an array of replacements, or if part of an object can access some other source (you should be able to specify a callback that references an object's method).

    This is in my opinion the cleanest method.

  • #9
    Regular Coder
    Join Date
    Apr 2003
    Location
    Montreal, QC
    Posts
    340
    Thanks
    3
    Thanked 2 Times in 2 Posts
    In the notes on the eval() man pages I found something similar, but not exactly like adrin's methos: use preg_replace with the e modifier. Then it eval()s only the part of the text that's being replaced. That in conjunction with a {$varname} construction should work. It works in my test function:
    PHP Code:
    function process($k) {
        global 
    $myname,$greeting;
        
        
    $message $greeting[$k];
        
        
    $message preg_replace('/\{(\$[^}]*)}/e''$1'$message);
        return 
    $message;

    It is also faster than eval()ing the whole string and, in my opinion safer.

    I put a $ in the capturing parentheses so the regexp will hopefully only capture variables and nothing else, (although, I guess it could capture object methods, maybe I need to do a little more work on the regex).

    This should remove the need of a huge array of possible replace values, although, now as I'm writing, I realize I have one already. I will experiment a little more.
    Search for Laughter or Just Search?
    GiggleSearch.org
    Blog: www.johnbeales.com
    All About Ballet: www.the-ballet.com

  • #10
    Regular Coder
    Join Date
    Apr 2003
    Location
    Montreal, QC
    Posts
    340
    Thanks
    3
    Thanked 2 Times in 2 Posts
    Well, I can't seem to make the variable variables work properly in the callback of preg_replace_callback, so I'll stick with the function posted above.
    Search for Laughter or Just Search?
    GiggleSearch.org
    Blog: www.johnbeales.com
    All About Ballet: www.the-ballet.com

  • #11
    Senior Coder
    Join Date
    Jan 2007
    Posts
    1,648
    Thanks
    1
    Thanked 58 Times in 54 Posts
    Just remember that eval() is the cheap way out and isn't a real solution. But more like a stopgap.

    Well, I can't seem to make the variable variables work properly in the callback of preg_replace_callback
    If done properly, it will work. But it depends on how much you want to do it the proper way (i.e. what level of quality is required).

  • #12
    Regular Coder
    Join Date
    Apr 2003
    Location
    Montreal, QC
    Posts
    340
    Thanks
    3
    Thanked 2 Times in 2 Posts
    Well, I realized that I would have the same variable scope issues with the function posted at 09:33, except that I wouldn't be able to solve them without calling both preg_match and preg_replace - not the ideal solution, so I kept working on the solution using preg_replace_callback and figured out a solution, (the problem I was having was an extra $ sign where it was not needed).

    So, here's my whole test script. The function that uses preg_replace_callback is cprocess(); It should handle coming across a plain variable and an array element in the string:

    PHP Code:
    <?php
    error_reporting
    (E_ALL);
    ini_set("display_errors","on");


    function 
    oprocess($k) {
        global 
    $myname,$greeting;
        
        
    $t $greeting[$k];
        
    $greeting[$k] = $t;
    //    echo $t.'<br/>';
        
    eval('$str = "'.addslashes($t).'";');
        
        return 
    $str;
        
    }


    function 
    process($k) {
        global 
    $greeting;
        
        
    $message $greeting[$k];
        
        
    $message preg_replace('/\{((\$[^\]}])[^}]*)}/e''$1'$message);
        return 
    $message;

    }

    function 
    cprocess($k) {
        
        if(!
    function_exists('callback')) {
            function 
    callback($arr) {
                
    $varname $arr[3];
        
    //        var_dump($arr);
        //        echo '<br/>';        
                
    global ${$varname};
                
        
    //        var_dump(${$varname});
                
                
    if(isset($$varname)) {
                    if(isset(
    $arr[4])) {
        
    //                echo '<br>returning: '.${$varname}[$arr[4]];
                        
    return ${$varname}[$arr[4]];
                    } else {
                        return ${
    $varname};
                    }    
                } else {
                    return 
    '';
                }
                
        
    //        echo $varname.'<br />';
        //        var_dump($$varname);
        //        print_r ($myname);
        //        echo $varname;
        //        echo '<br /><br />';
                
                
    return 'test';
            
            }
        }
        global 
    $greeting;
        
    $message $greeting[$k];
        
        
    $message preg_replace_callback('/(\{\$(([^\[}]+)\[?([^\]+])?[^}]*)})/''callback'$message);
        return 
    $message;

    }


    $greeting = array('gr'=>'Hi there {$myname[1]}, {$myname[0]}');

    $myname = array('John','Frank');

    // a timer to test performance
    /* 
    $stime = microtime();
    $i=0;
    while($i < 1000000) {
    $str = cprocess('gr');
    $i++;
    }
    $etime = microtime();
    echo 'time: '.($etime - $stime).'<br />'; 
    */

    echo cprocess('gr');


    ?>
    It does run more slowly than even eval()ing the whole string, but there is no eval involved, so I'm much happier.
    Search for Laughter or Just Search?
    GiggleSearch.org
    Blog: www.johnbeales.com
    All About Ballet: www.the-ballet.com


  •  

    Posting Permissions

    • You may not post new threads
    • You may not post replies
    • You may not post attachments
    • You may not edit your posts
    •