Search code examples
phppass-by-referencepreg-replace-callback

PHP: call-time pass-by-reference broke my array_walk and I can't fix it


Here is the PHP code before deprecation errors were introduced:

array_walk( $tags, 'shortcode_tag_parse', &$content );

function shortcode_tag_parse( &$tag, $key, &$content ) {

    $content = preg_replace_callback( "{\[{$tag}[^\]]*\].*?\[/{$tag}\]}is", 'shortcode_img_unautop', $content );

}

// Replace <p> tags around images
function shortcode_img_unautop( $match ) {

    return preg_replace( '#\s*<p>\s*(<a .*>)?\s*(<img .*>)\s*(<\/a>)?\s*<\/p>\s*#iU', '\1\2\3', $match[0] );

}

Now if I remove the call-time reference:

array_walk( $tags, 'shortcode_tag_parse', $content );

It no longer modifies $content, and I absolutely need to do this. I will not settle for switching to a loop. The other topics I've looked at simply say to remove the call-time reference &, and when I did that, it no longer does what it was supposed to do.

Does anyone know how I can get my code to work again, without the need for looping (array_walk and array_map look better for me).


Solution

  • As mentioned in the comments, your best bet here is a reimplementation of array_walk that expects the last parameter to be a reference. Call-time pass-by-ref to builtins is dangerous and was basically universally removed after some pretty harsh security exploits.

    Here's an entirely untested example.

    function array_walk_userdata_by_ref(array &$array, $callback, &$userdata = null) {
        foreach($array as $k => $v) {
            $array[$k] = $callback( $v, $k, $userdata );
        }
    }