【问题标题】:PHP segfault when spread operator is applied to object将扩展运算符应用于对象时的PHP段错误
【发布时间】:2017-11-09 16:31:15
【问题描述】:

FINAL EDIT :: 查看答案


好的,给定这段代码

private function select(string $key, string ...$keys): Model
{
    \array_unshift($keys, $key);

    foreach($keys as &$key)
    {
        $key = \preg_replace_callback('/([a-zA-Z]+)\((.*)\)/', function($match){
        return \sprintf('%s(%s)', $match[1], $this->primaryFields()->keys()->first());
    }, $key);
}

在这种情况下,写入密钥的行是段错误,起初我认为这是因为 Prce 发生了一些奇怪的事情。但是,当我用字符串文字设置它时,也会发生同样的情况。最后,我通过注释掉array_unshift 解决了这个问题。从某种意义上说,我可以创建一个新数组来“取消移动”$key 参数,但我认为没有必要这样做,有谁知道这是 PHP 的怪癖,还是我在这里误解了什么?

顺便说一句,我正在以 fpm 运行 php7.1


编辑::

好的,我正在写我正在开发的整个故事,但我似乎已经查明原因,它是一个sprintf,特别是这个块

$keys = \array_map(function($key){
    $matches = Regex::match('/([a-zA-Z]+)\((.*)\)/', $key);

    $string = \key_exists(2, $matches)
        ? $matches[2]
        : $key;

    if(\count($matches) > 0)
    {
        $format = \sprintf('%s(%%s.`%%s`)', $matches[1]);
    }
    else
    {
        $format = $string === '*'
            ? '%s.%s'
            : '%s.`%s`';
    }

    return \sprintf($format, $this->owner->getTarget(), $string);
}, $this->keys);

回调最后一行的sprintf 是segfaults,当且仅当格式由if创建时,当它通过else时工作正常。

我创建格式的方式不允许?据我所知,它确实为“'count(%s.%s)”创建了一个有效格式,更多的测试告诉我,当我将 if 中的 $format 分配更改为 $format = '%s.%s@987654331 @我仍然遇到段错误。

最奇怪的是,昨天当我进行精确定位时,我得到了所有......虽然输入这个 php 似乎已经决定这个代码现在是正确的......我昨天想说的是它没有'直到在 zf3 中调用 new PDO 才出现段错误...

我真的迷失了在哪里看......

【问题讨论】:

  • 如果出现段错误,您可以 100% 确定 PHP 本身已经失败并且您发现了一个错误。 然而,你的代码也很模糊(提示:$key 循环内外),你也不应该这样写。
  • 无法重现:3v4l.org/gpIV9 - 你能提供一个可重现的测试用例吗?
  • PHP 错误日志中有什么内容?
  • 您能否对您传入的数据进行快照,并尝试制作一个独立的可重现测试用例。很有可能这很难做到,因为它可能是其他地方的错误,恰好是这里的问题。 :-/
  • @Narf 我也有同样的想法并做了一些尝试,但这并没有解决任何问题,因为 $key 只是被覆盖了 @Gordon 我认为它会很大,我们正在谈论自定义ORM big @JesseSchokker 不,我看的第一个地方,服务器上与 webrequests 相关的任何日志都没有错误@Danack 不确定我是否可以这是建立在 zend 框架 3 之上的

标签: php segmentation-fault php-7.1


【解决方案1】:

好吧,长话短说,它与正则表达式或数组移位无关。事实证明,...(spread) 运算符应用于具有 ArrayAccess、IteratorAggregate 等的对象,使该对象作为数组工作的所有内容,在使用 ... 运算符调用时似乎随机出现段错误。


即给定这个类签名,我们能够像处理一个数组一样处理这个类(这里没有实现细节以节省解释空间)

class Foo implements \ArrayAccess, \IteratorAggregate
{
    public function getIterator()

    public function offsetExists($offset)
    public function offsetGet($offset)
    public function offsetSet($offset, $value)
    public function offsetUnset($offset)
}

$foo = new Foo;
$foo[] = 'one';
$foo[] = 'two';
$foo[] = 'three';

好的,让我们同意$foo 包含树添加的项目。如果$fooarray,我们可以做function(...$foo),这将导致函数调用function('one', 'two', 'three')。对?好吧,当我在我的代码中使用我的Collection 类(在某种意义上是我的Foo)执行此操作时,它会出现段错误(并非总是如此,只是在某些情况下,并且没有;没有定义键,我测试了它,并且与数组一样,它会给出错误“无法用键解压数组”)。


我仍然不知道为什么它只是我的解决方法是将我的Collection 转换为array 的段错误。我也不知道这是否是 PHP 的已知错误,也不知道如何真正搜索它。


TL;DR :: 使用 ... 运算符解包时,请确保您尝试解包的是 array ;)

【讨论】:

  • 对于那些好奇的人,我们今天在 PHP7.2RC6 中测试了代码库,并且段错误仍然存​​在
  • 如果您发现了可重现的崩溃,请在 bugs.php.net 上报告。 PHP 不应该出现段错误。
  • @Andrea 这确实是一个错误,我已经报告了它,此修复程序随 PHP7.2.2 提供
猜你喜欢
  • 2019-09-29
  • 1970-01-01
  • 2021-04-09
  • 2021-12-28
  • 2020-06-24
  • 2017-02-23
  • 2017-11-04
  • 2018-04-14
  • 2017-12-30
相关资源
最近更新 更多