Symfony 1.4在PHP 5.5中使用了被弃用的函数

18
我最近将PHP从版本5.3.27升级到了5.5.0。 在我的Symfony2.3.2项目中一切都运行良好,我可以享受最新的PHP功能。
现在当我回到我的其他Symfony1.4.16项目时,我会收到一个关于preg_replace具有/e修饰符已被弃用的PHP错误。
我在论坛上找不到关于这个错误的参考:有人之前遇到过这个问题吗?有没有任何可以直接应用的补丁?升级到Symfony 1.4.20是否会解决此问题?
错误消息如下所示:
Deprecated: preg_replace(): The /e modifier is deprecated, use preg_replace_callback instead in /myproject/lib/vendor/symfony/lib/response/sfWebResponse.class.php on line 409
一个方法是按照手册和信息建议修改代码。 我该如何将我的preg_replace表达式更改为preg_replace_callback调用?
任何帮助/提示都将非常欢迎。
编辑:
截至目前,这个问题还没有补丁(Symfony 1.4.20也没有解决这个问题)。解决方法是在源代码中将失败的preg_replace调用替换为相应的preg_replace_callback调用,在sfWebResponse类中很容易实现(感谢Jon的提示)。现在下一个失败的事件稍微复杂一些,不幸的是……另一方面,我们可能需要使用/e选项来搜索preg_replace使用情况,以找出Symfony可能会出问题的地方。这会得到相当多的结果:o 因此......我的结论是,直到出现一些严重的补丁之前,Symfony 1.4用户最好不要升级PHP到5.5版本。你认为呢?有别的选择吗?

2
这个问题在Symfony 1.4.x中没有被修复。您应该自行打补丁。如果您能在我们的 Symfony1上提交拉取请求以进行更改,那就太棒了 :) - j0k
@Jon 这里的主要问题是让Symfony 1.4与PHP 5.5兼容。从这个意义上说,我认为它不是重复的(我会保留原来的标题:o)。你觉得呢?我同意用preg_replace_callback替换preg_replace是解决问题的方法,但之前的帖子并没有完全解决这个问题... - mika
@mika:可能吧……问题是以“如何修改代码”开头的,这就是我回答的内容,但接下来又问到了补丁和可能的未来更新——这些都应该去Symfony开发者资源中寻找答案。(我看到1.4.x已经8个月没有提交过任何内容了,所以我不指望这会在原版Symfony中得到修复)。也许我被“429行”这个太具体的部分带走了。无论如何,在我看来,问题的目的应该得到澄清。 - Jon
@Jon:当然,我开始尝试回答我的问题之前,实际上还没有完全构思清楚。我错了(让我重新表述一下)。你的答案对于深入挖掘非常有帮助。现在在更大的背景下,编辑Symfony 1.4代码似乎不是最简单的解决方法。 - mika
许多symfony1 preg_replace()弃用问题已经在@j0k的symfony1分支中得到修复。请参阅此拉取请求差异以了解如何解决这些问题:https://github.com/LExpress/symfony1/pull/26/files - John Kary
7个回答

37

除非您在index.php中启用了调试模式,否则这些错误不会出现在产品中。 在settings.yml中取消E_DEPRECATED标志也可以在开发环境中去除这些错误:

dev:
  .settings:
    error_reporting:  <?php echo ((E_ALL | E_STRICT) ^ E_DEPRECATED)."\n" ?>

那一个快速且简单的解决方案 :) 非常感谢! - mika
5
这不是一个解决方案!你应该修复代码,并且下面的评论使xtech能够修复了sfToolkit.class.php,而mika则修复了sfWebResponse.class.php(他也提供了第二个文件的修复方案,但对我来说无效,会导致致命错误)。 - Radamanf
重复的https://dev59.com/o3vaa4cB1Zd3GeqPAz1C#25156792 - Radamanf
绝对不是最好的解决方案来隐藏某些不起作用的东西,仅仅是为了说“现在它运作正常!”-_- - j0k
5
如下所建议的,最好的选择是使用社区维护版本的Symfony1......它类似于Symfony 1.5:https://github.com/LExpress/symfony1。完全兼容PHP 5.5和5.6。 - Zoltan
1
感谢@szines发布链接。我正在维护我们复杂的生产Symfony 1.4应用程序,这可能会为我们节省一些时间。我希望SensioLabs早些时候就放了一个链接到那个分支,这是我第一次听说它。 - ybull

14

基本上,您需要从 preg_replace 调用中获取替换参数,并将其分解为适当的PHP表达式,然后将该表达式作为函数体,用作相应的 preg_replace_callback 调用的回调。

在您的情况下,相关代码如下:

return preg_replace('/\-(.)/e', "'-'.strtoupper('\\1')", /* input */)

那么你可以这样做

$callback = function($matches) {
    return '-'.strtoupper($matches[1]);
};

return preg_replace_callback('/\-(.)/', $callback, /* input */)

正如您所看到的,回调代码与原始替换表达式完全相同,唯一的区别是像 $matches[1] 这样的数组访问将取代诸如 \\1 的引用。


这看起来非常不错,并提供了一个修复错误消息的方法。现在,在我的项目/ lib / vendor / symfony / lib / util / sfToolkit.class.php的第362行,我遇到了同样的问题。这意味着代码需要在我使用的Symfony版本的各个地方进行更新... :/ @jOk 哦,好的,这与您上面的评论相匹配 :) 您的意思是这是我参与Symfony源代码的机会?听起来不错 :) - mika
我只需要更改 /lib/vendor/symfony/lib/response/sfWebResponse.class.php,谢谢! - Arkadiusz Cieśliński

11
总之,最好的解决方案是避免升级PHP到5.5版本,因为它不再与Symfony 1.4兼容。
如果您在开发环境中同时拥有Symfony 2和1.4版本,则可以像这里所描述的那样切换PHP版本。
如果您确实需要,可以在同一Apache服务器上同时设置两个不同版本的PHP:这需要进行更多配置,上述链接也解释了这一点。
替代热修复方法:
通过对Symfony代码进行一些更新,我可以在开发环境中使大部分网页运行。当然,在生产环境中应用此方法可能存在风险,因为"已过时"的错误随时可能出现,来自另一个Symfony库。
在myproject/lib/vendor/symfony/lib/response/sfWebResponse.class.php的409行,我现在有以下代码(注释掉的是原始Symfony代码):
  protected function normalizeHeaderName($name)
  {
    // return preg_replace('/\-(.)/e', "'-'.strtoupper('\\1')", strtr(ucfirst(strtolower($name)), '_', '-'));    

    return preg_replace_callback(
                  '/\-(.)/', 
                  function ($matches) {
                    return '-'.strtoupper($matches[1]);
                  }, 
                  strtr(ucfirst(strtolower($name)), '_', '-')
        );
  }

在myproject/lib/vendor/symfony/lib/util/sfToolkit.class.php文件的362行,我们得到:

  public static function pregtr($search, $replacePairs)
  {
    // return preg_replace(array_keys($replacePairs), array_values($replacePairs), $search);
    foreach($replacePairs as $pattern => $replacement)
        $search = preg_replace_callback(
                    $pattern, 
                    function ($matches) use ($replacement){
                        if(array_key_exists(1, $matches)){ $replacement = str_replace("\\1", $matches[1], $replacement);}
                        if(array_key_exists(2, $matches)){ $replacement = str_replace("\\2", $matches[2], $replacement);}
                        return $replacement;
                    }, 
                    $search
                );
    return $search;
  }

使用时请自行承担风险 :)


为什么需要修改 pregtr 函数?它不使用 /e。顺便说一句,我们知道 这个问题已在 GitHub 上开放讨论 - j0k
@jOk pregtr带有两个参数,这两个参数用于preg_replace调用。事实证明$search参数有时会使用/e选项,这就是为什么需要在此更改preg_replace调用的原因。同样,当前Symfony代码在pregtr调用中最多使用两个匹配模式,因此我提出的补丁也正常工作(只使用array_key_exists 1和2,而不是3、4、5等等)。如果有更通用的解决方法,我会很高兴看到它 :) 哦,谢谢您提出的问题。这是一个好消息。 - mika
2
除非您在index.php中启用了调试,否则该错误不会在生产环境中显示。在开发环境中,也可以通过取消settings.yml中的E_DEPRECATED标志来删除它们:<?php echo ((E_ALL | E_DEPRECATED) ^ E_DEPRECATED)."\n" ?>。 - flm
@flm:这是我正在寻找的快速解决方案。如果您将您的提示放在帖子中,我将标记它为正确答案。非常感谢! - mika
@flm 静音所有消息是不好的做法,你们最好立即修复这些小问题,感谢谷歌搜索和之前做过的人们 :)。 - Arkemlar

11

/lib/vendor/symfony/lib/response/sfWebResponse.class.php的normalizeHeaderName方法修复,位于407行。

protected function normalizeHeaderName($name)
{
  //return preg_replace('/\-(.)/e', "'-'.strtoupper('\\1')", 
  strtr(ucfirst(strtolower($name)), '_', '-');
  return str_replace(array('\'$1$3\'','\'$2$4\'','\'$1\'', '\'$2\'', '$1', '$2'),array('$matches[1].$matches[3]','$matches[2].$matches[4]','$matches[1]','$matches[2]','$matches[1]','$matches[2]'),
$name);
}

修复 /lib/vendor/symfony/lib/util/sfToolkit.class.php 第360行的 pregtr 方法问题

public static function pregtr($search, $replacePairs){
  // return preg_replace(array_keys($replacePairs), array_values($replacePairs), $search);
  foreach($replacePairs as $pattern => $replacement)
  {
    if (preg_match('/(.*)e$/', $pattern, $matches))
    {
      $pattern = $matches[1];
      $search = preg_replace_callback($pattern, function ($matches) use ($replacement) {
        preg_match("/('::'\.)?([a-z]*)\('\\\\([0-9]{1})'\)/", $replacement, $match);
        return ($match[1]==''?'':'::').call_user_func($match[2], $matches[$match[3]]);
      }, $search);
    }
    else
    {
      $search = preg_replace($pattern, $replacement, $search);
    }
  }
  return $search;
}

8

5

替代方法:修复在 /lib/vendor/symfony/lib/util/sfToolkit.class.php 的第 360 行中的 pregtr 方法

public static function pregtr($search, $replacePairs)
{
  // return preg_replace(array_keys($replacePairs), array_values($replacePairs), $search);
  foreach($replacePairs as $pattern => $replacement)
  {
    if (preg_match('/(.*)e$/', $pattern, $matches))
    {
      $pattern = $matches[1];
      $search = preg_replace_callback($pattern, function ($matches) use ($replacement) {
        preg_match("/('::'\.)?([a-z]*)\('\\\\([0-9]{1})'\)/", $replacement, $match);
        return ($match[1]==''?'':'::').call_user_func($match[2], $matches[$match[3]]);
      }, $search);
    }
    else
    {
      $search = preg_replace($pattern, $replacement, $search);
    }
  }
  return $search;
}

0
Deprecated: preg_replace(): The /e modifier is deprecated, use preg_replace_callback instead in lib/vendor/symfony/…This changelog will solve the problem for all symfony 1.4.x. Tested on Symfony 1.4.20
---
 lib/vendor/symfony/lib/command/sfCommandManager.class.php     |  4 +++-
 lib/vendor/symfony/lib/form/addon/sfFormObject.class.php      |  2 +-
 lib/vendor/symfony/plugins/sfDoctrinePlugin/lib/form/sfFormFilterDoctrine.class.php  |  2 +-
 lib/vendor/symfony/plugins/sfPropelPlugin/lib/form/sfFormFilterPropel.class.php      |  2 +-
 lib/vendor/symfony/lib/response/sfWebResponse.class.php       |  2 +-
 lib/vendor/symfony/lib/util/sfInflector.class.php             |  5 +----
 lib/vendor/symfony/lib/util/sfToolkit.class.php               | 11 +++++++++++
 7 files changed, 19 insertions(+), 9 deletions(-)

lib/vendor/symfony/lib/command/sfCommandManager.class.php
@@ -108,7 +108,9 @@ class sfCommandManager
     else if (!is_array($arguments))
     {
       // hack to split arguments with spaces : --test="with some spaces"
-      $arguments = preg_replace('/(\'|")(.+?)\\1/e', "str_replace(' ', '=PLACEHOLDER=', '\\2')", $arguments);
+      $arguments = preg_replace_callback('/(\'|")(.+?)\\1/', function($matches) {
+         return str_replace(' ', '=PLACEHOLDER=', $matches[2]);
+     }, $arguments);
       $arguments = preg_split('/\s+/', $arguments);
       $arguments = str_replace('=PLACEHOLDER=', ' ', $arguments);
     }

lib/vendor/symfony/lib/form/addon/sfFormObject.class.php
@@ -278,6 +278,6 @@ abstract class sfFormObject extends BaseForm

   protected function camelize($text)
   {
-    return preg_replace(array('#/(.?)#e', '/(^|_|-)+(.)/e'), array("'::'.strtoupper('\\1')", "strtoupper('\\2')"), $text);
+    return sfToolkit::camelize($text);
   }
 }

lib/vendor/symfony/lib/plugins/sfDoctrinePlugin/lib/form/sfFormFilterDoctrine.class.php
@@ -323,7 +323,7 @@ abstract class sfFormFilterDoctrine extends sfFormFilter

   protected function camelize($text)
   {
-    return sfToolkit::pregtr($text, array('#/(.?)#e' => "'::'.strtoupper('\\1')", '/(^|_|-)+(.)/e' => "strtoupper('\\2')"));
+    return sfToolkit::camelize($text);
   }

   protected function getTable()

lib/vendor/symfony/lib/plugins/sfPropelPlugin/lib/form/sfFormFilterPropel.class.php
@@ -263,6 +263,6 @@ abstract class sfFormFilterPropel extends sfFormFilter

   protected function camelize($text)
   {
-    return sfToolkit::pregtr($text, array('#/(.?)#e' => "'::'.strtoupper('\\1')", '/(^|_|-)+(.)/e' => "strtoupper('\\2')"));
+       return sfToolkit::camelize($text);
   }
 }

lib/vendor/symfony/lib/response/sfWebResponse.class.php
@@ -406,7 +406,7 @@ class sfWebResponse extends sfResponse
    */
   protected function normalizeHeaderName($name)
   {
-    return preg_replace('/\-(.)/e', "'-'.strtoupper('\\1')", strtr(ucfirst(strtolower($name)), '_', '-'));
+    return preg_replace_callback('/\-(.)/', function ($matches) { return '-'.strtoupper($matches[1]); }, strtr(ucfirst(strtolower($name)), '_', '-'));
   }

   /**

lib/vendor/symfony/lib/util/sfInflector.class.php
@@ -28,10 +28,7 @@ class sfInflector
   public static function camelize($lower_case_and_underscored_word)
   {
     $tmp = $lower_case_and_underscored_word;
-    $tmp = sfToolkit::pregtr($tmp, array('#/(.?)#e'    => "'::'.strtoupper('\\1')",
-                                         '/(^|_|-)+(.)/e' => "strtoupper('\\2')"));
-
-    return $tmp;
+    return sfToolkit::camelize($tmp);;
   }

   /**

lib/vendor/symfony/lib/util/sfToolkit.class.php
@@ -608,4 +608,15 @@ class sfToolkit

     return set_include_path(join(PATH_SEPARATOR, $paths));
   }
+
+   public static function camelize($text)
+   {
+       if (preg_match('#/(.?)#', $text, $matches)) {
+           $text = str_replace($matches[0], '::'.strtoupper($matches[1]), $text);
+       }
+       if (preg_match('/(^|_|-)+(.)/', $text, $matches)) {
+           $text = str_replace($matches[0], strtoupper($matches[2]), $text);
+       }
+       return $text;
+   }
 }
--

以下是有关编程的英文内容,翻译成中文。请仅返回已翻译的文本:这次贴出了http://blog.jakoubek.cz/symfony-1-4-deprecated-e-modifier上的内容,希望能帮助到您。 - ImLeo
这是这里最全面的答案 - Nate
这对于阅读和理解来说非常糟糕。欢迎提供Github链接。 - Arkemlar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接