开发者

PHP: Weird function behavior depends on how I include the script it's contained in? I'm at a loss

I honestly have little clue what facts are relevant to this issue, so I'll go from the beginning.

I have bits of text that I'd like to format Markdown-style urls in before plugging into a template, but I don't want them to be wrapped in <p>'s or any other block-level tags.

To do this, I worked my way through the PHP Markdown code, isolated the stuff needed for the url formatting and threw the functions together into a file called 'MarkdownUrl.php' in a folder called 'functions' at my include path.

I'll post that code at the bottom.

For now, let's test it:

<?php

require_once 'functions/MarkdownUrl.php';

$text = "Hello, world. [This is a link.](http://www.google.com)";

echo MarkdownUrl($text);

?>

Output:

Hello, world. This is a link.

So far so good.

I also have a file called 'loader.php' at the include path. It contains a class autoloading function which it registers with spl_autoload_register() and another function called loadFunc() which will require_once a php file from the 'functions' directory according to the name it's passed. The latter is what matters here.

<?php

function loadFunc($funcName)
{
    if (!function_exists($funcName)) {
        require_once 'functions/' . $funcName . '.php';
    }

}

function loadClass($className)
{
    if (!class_exists($className, false)) {
        $classPath = str_replace('_', '/', $className);
        require_once 'classes/' . $classPath . '.php';
    }

}

spl_autoload_register('loadClass');

?>

Ignoring the 'whys' and 'wherefores' of including code in this manner for the moment, the following should be effectively equivalent to the test code I posted earlier, right?

<?php

require_once 'loader.php';
loadFunc('MarkdownUrl');

$text = "Hello, world. [This is a link.](http://www.google.com)";

echo MarkdownUrl($text);

?>

And, yet... output:

Hello, world. [This is a link.](http://www.google.com)

No errors are issued on running the above.

And, I have confirmed that the function MarkdownUrl() is being called (at least, a test echo I inserted at the top of the function fired).

Yet, the output is unformatted. WTF?

A couple I'm-not-sure-if-these-matter-at-all details: shared web host, include path specified via php.ini file in directory the test script runs in.


Contents of MarkdownUrl.php:

<?php

$nested_brackets_depth = 6;
$nested_url_parenthesis_depth = 4;
$no_entities = false;

function doAnchors_inline_callback($matches) {
    $whole_match    =  $matches[1];
    $link_text      =  $matches[2];
    $url            =  $matches[3] == '' ? $matches[4] : $matches[3];
    $title          =& $matches[7];

    $url = encodeAttribute($url);

    $result = "<a href=\"$url\"";
    if (isset($title)) {
        $title = encodeAttribute($title);
        $result .=  " title=\"$title\"";
    }

    $result .= ">$link_text</a>";

    return $result;
}

function encodeAttribute($text) {
#
# Encode text for a double-quoted HTML attribute. This function
# is *not* suitable for attributes enclosed in single quotes.
#
    $text = encodeAmpsAndAngles($text);
    $text = str_replace('"', '&quot;', $text);
    return $text;
}

function encodeAmpsAndAngles($text) {

    global $no_entities;

#
# Smart processing for ampersands and angle brackets that need to 
# be encoded. Valid character entities are left alone unless the
# no-entities mode is set.
#
    if ($no_entities) {
        $text = str_replace('&', '&amp;', $text);
    } else {
        # Ampersand-encoding based entirely on Nat Irons's Amputator
        # MT plugin: <http://bumppo.net/projects/amputator/>
        $text = preg_replace('/&(?!#?[xX]?(?:[0-9a-fA-F]+|\w+);)/', 
                            '&amp;', $text);;
    }
    # Encode remaining <'s
    $text = str_replace('<', '&lt;', $text);

    return $text;
}

function MarkdownUrl($text) {

    global $nested_brackets_depth, $nested_url_parenthesis_depth;

    $nested_brackets_re = 
            str_repeat('(?>[^\[\]]+|\[', $nested_brackets_depth).
            str_repeat('\])*', $nested_brackets_depth);

    $nested_url_parenthesis_re = 
            str_repeat('(?>[^()\s]+|\(', $nested_url_parenthesis_depth).
            str_repeat('(?>\)))*', $nested_url_parenthesis_depth);

    $text = preg_replace_callback('{
        (               # wrap whole match in $1
          \[
            ('.$nested_brackets_re.')   # link text = $2
          \]
          \(            # literal paren
            [ \n]*
            (?:
                <(.+?)> # href = $3
        开发者_Go百科    |
                ('.$nested_url_parenthesis_re.')    # href = $4
            )
            [ \n]*
            (           # $5
              ([\'"])   # quote char = $6
              (.*?)     # Title = $7
              \6        # matching quote
              [ \n]*    # ignore any spaces/tabs between closing quote and )
            )?          # title is optional
          \)
        )
        }xs','doAnchors_inline_callback', $text);

    return $text;
}

?>


That happens because you have different variable scopes in your cases.

In first case your variables are defined in global scope, thus $nested_brackets_depth = 6; and other vars defined in MarkdownUrl.php are visible for markdown functions

In other case - that variables are defined in function that includes the file scope, so they are not visible inside the functions.

The solution: change markdown file header to

global $nested_brackets_depth = 6;
global $nested_url_parenthesis_depth = 4;
global $no_entities = false;

Btw, it is a great sample why global is evil and why defining/accessing the variables in global scope is evil too.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜