简体   繁体   中英

PHP can't find dynamically generated function

Note: While the issue occurred trying to solve a WordPress problem, the problem being faced right now (see "Current Approach", below) is clearly a PHP issue, which is why it's been posted here.

TL;DR:

I'm dynamically generating PHP code in a file and including that file after it's finished being written to, however PHP cannot call functions from inside the file—even when including it directly without making any changes.

Preface

I've been working on a system for dynamically generating shortcodes in WordPress, and have been running into one serious roadblock along the way: Registering the functions for the shortcodes.

Long story short is that we've got a list of options stored in an array similar to the following:

$array = array(
    0 => array(
        'code' => 'my-shortcode',
        'replacement' => 'replacement_directives_here'
    )
);

I've already got a system that processes the codes and sends generates the proper output based on the directives. It's getting the call to add_shortcode($shortcode, $callback) to work.

My first strategy was to use anonymous functions in a manner similar to the following:

foreach ($array as $code => $directions) {
    $GLOBALS['my_shortcode_output'] = my_shortcode_process($directions);

    add_shortcode($code, function() { return $GLOBALS['my_shortcode_output']; });
}

However this ended up with successive directives overwriting each other due to the fluctuating content of the global, so I decided to try something different...

Current Approach

As a workaround to having the information I need constantly slipping just out of reach, I decided to try something different:

  • Create a file within my plugin
  • Write out the PHP code for the functions I wanted to include so that they were guaranteed to generate the right output
  • Include the file after the fclose() call
  • Register the shortcodes, referencing the functions in the new file

The code for generating the file looks something like the following:

$file = fopen(PATH_TO_FILE, 'w'); // Open for writing only, truncate file on opening
fwrite($file, "<?php\n\n"); // Using double quotes so newlines and escapes don't get counted as literals

// foreach through list
foreach ($shortcode_list as $shortcode) {
    if ($shortcode['code'] != '') {
        // Append new function with a dynamic name (e.g. $shortcode[code]._sc') to dynamic_shortcodes.php
        // Function should consist of: return my_shortcode_process($shortcode['replacement']);
        // Hard-coding so we don't get frozen if information gets changed
        $new_function = "\tfunction str_replace('-', '_', $shortcode['code'])."_sc() {\n\t\treturn my_shortcode_process('".$shortcode['replacement']."');\n\t}\n\n";

        fwrite($file, $new_function);

        // Add function name to $shortcode_functions array, keyed on the shortcode
        $shortcode_functions[$shortcode['code']] = str_replace('-', '_', $shortcode['code']).'_sc';
    }
}

fclose($file); // Close the file, since we are done writing to it
touch(PATH_TO_FILE); // Ensure the file's modification time is updated

After that it's just a simple loop to register them:

foreach ($shortcode_functions as $shortcode => $callback) {
    add_shortcode($shortcode, $callback);
}

When I reload and run everything, however, I get the following:

Notice: do_shortcode_tag was called incorrectly. Attempting to parse a shortcode without a valid callback: [SHORTCODE HERE] . Please see Debugging in WordPress for more information.

I've downloaded the file and verified its contents—everything checks out in PHPstorm. It's properly formatted, there are no syntax errors, and the functions it depends upon are already loaded and working fine.

Even skipping the whole process and just directly including the file and then calling one of the functions inside it isn't working. It's like the file has been blackballed. At the same time, however, neither include() nor require() produce any errors.

Is this a caching issue, perhaps?

Honestly, I'm totally unable to understand what you're trying to do (or even why) but PHP doesn't have any problem with dynamically generated includes. This works fine:

<?php

$file = __DIR__ . '/foo-' . mt_rand(0, PHP_INT_MAX) . '.php';
$code = '<?php

function foo() {
    echo "Hello, World!";
};
';
file_put_contents($file, $code);

require $file;
foo();

However, you're apparently trying to execute something like this:

function str_replace('-', '_', $shortcode['code'])."_sc(){
}

That's a blatant syntax error either in included files on in the main script. If you follow the Please see Debugging in WordPress for more information instructions you'll possibly find something similar to this:

Parse error: syntax error, unexpected ''-'' (T_CONSTANT_ENCAPSED_STRING), expecting variable (T_VARIABLE)

A syntax for variable functions that works could be:

$name = str_replace('-', '_', $shortcode['code']) . '_sc';
$name = function (){
};

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM