PHP segfault, когда оператор распространения применяется к объекту
ОКОНЧАТЕЛЬНОЕ РЕДАКТИРОВАНИЕ:: Посмотрите на ответ
Хорошо, учитывая этот фрагмент кода
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, или я что-то здесь неправильно понял?
Кстати, я запускаю php7.1 как fpm
РЕДАКТИРОВАТЬ::
Хорошо, я писал целую историю о том, что я разрабатываю, Но, кажется, я точно определил причину, это 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, работает нормально.
Я способ, которым я создаю свой формат, не разрешен? is действительно создает допустимый формат для, насколько я знаю, "'count(%s.%s
)", еще несколько тестов показывают мне, что когда я изменяю назначение $format
в if на $format = '%s.
%s'
Я все еще получаю segfault.
Самое странное, что вчера, когда я делал укол, я получил все... При вводе этого php, похоже, решил, что теперь этот код подходит.. То, что я пытался сказать, что вчера это не произошло, пока в zf3 new PDO
не было называется...
Я действительно не знаю, где искать...
1 answers
Хорошо, короче говоря, это не имело никакого отношения к регулярным выражениям или сдвигам массивов. Оказывается, что оператор ...
(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
содержит добавленные элементы дерева. если бы $foo
было array
, мы могли бы сделать function(...$foo)
, что привело бы к вызову функции function('one', 'two', 'three')
. верно? хорошо, тогда, когда я сделал это в своем коде с моим классом Collection
(в некотором смысле, с моим классом Foo
), он будет сегментирован (не всегда, только с определенными экземплярами, и нет; ключи не были определены, я проверил это, и, как и с массивом, он выдаст ошибку "не удается распаковать массив с ключами").
Я все еще понятия не имею, почему это так просто, что мой обходной путь состоит в том, чтобы привести мой Collection
к array
. Я также не знаю, является ли это известной ошибкой в PHP и как ее действительно искать.
TL;DR::при использовании оператора ...
для распаковки убедитесь, что то, что вы пытаетесь распаковать, является array
;)