[PHP7.4] ginq の デバッグ
PHP と PHPUnit のバージョンアップをマージしてもらった。
PHP7.4 にバージョンアップしたら toArray で止まる原因を追求
どこでおちるか追跡
なお、PHPUnit 9.4.4
public static function toArray($it)
{
$num = count($it);
$cur = 0;
var_dump('>>> in for ');
$acc = array();
foreach ($it as $k => $v) {
++$cur;
var_dump($cur);
$acc[$k] = $v;
}
var_dump('<<< out for ');
return $acc;
}
ErrorException: count(): Parameter must be an array or an object that implements Countable
/work/vendor/ginq/ginq/src/Ginq/Util/IteratorUtil.php:116
/work/vendor/ginq/ginq/src/Ginq/Ginq.php:156
$it が Countable
じゃないようだ
- $num = count($it);
+ $num = is_countable($it) ? count($it) : $it->count();
Error: Call to undefined method Ginq\Iterator\OrderedIterator::count()
/work/vendor/ginq/ginq/src/Ginq/Util/IteratorUtil.php:116
/work/vendor/ginq/ginq/src/Ginq/Ginq.php:156
左様か
count するのはあきらめたら話が進んだが、どうやらいっちゃいけないところまでいっちゃってるっぽい
9 件でぐるぐる回るはずが、$cur が 25 まで進んでる
果てに出ているエラー
Trying to access array offset on value of type null
これじゃなかった。。(ちゃんと抜け出てた)
toList
public static function toList($it)
{
$acc = array();
foreach ($it as $v) { // <- ここで落ちる場合があるっぽい
$acc[] = $v;
}
return $acc;
}
$it の 中身は var_dump した結果、 Ginq\Iterator\JoinIterator
これの $this->it はどうやら↓で生成されている(new SelectManyWithJoinIterator)ようで、コンストラクタは通過していた
引き続き ↓(SelectManyWithJoinIterator # rewind)を追う。。
環境上の理由で必殺 var_dump デバッグしてたら
public function rewind()
{
var_dump('rewind start');
$this->outer->rewind();
var_dump('rewind 1');
$this->fetchOuter();
var_dump('rewind 2');
$this->fetchInner();
var_dump('rewind end');
}
string(12) "toList start"
string(26) "Ginq\Iterator\JoinIterator"
string(14) "__construct in"
string(15) "__construct out"
string(12) "rewind start"
string(8) "rewind 1"
string(8) "rewind 2"
rewind end
が出てない・・・
で、次の var_dump を打ち込むまえに GitHub のソースを見たら、違いに気付いた。
public function rewind()
{
$this->outer->rewind();
$this->fetchOuter();
$this->skipEmpty(); // <- !!!
$this->fetchInner();
}
というわけで、 プルリクを出すことにした。
メンションしたいと思って検索したら作者が見つかった
"require": {
- "ginq/ginq": "~0.2.3"
- "ginq/ginq": "~0.2.4" // rewind の内容変わってなかった
+ "ginq/ginq": "dev-master"
}
にしてソースを最新にしたが、toList でまだ落ちるようだ。つづく。
refs
public function rewind()
{
var_dump('rewind 0');
$this->outer->rewind();
var_dump('rewind 1');
$this->fetchOuter();
var_dump('rewind 2');
$this->skipEmpty();
var_dump('rewind 3');
$this->fetchInner();
var_dump('rewind 4');
}
こうしたところ
string(8) "rewind 0"
string(8) "rewind 1"
string(8) "rewind 2"
string(8) "rewind 3"
E
こうなったので、fetchInner を追う
なお、PHPUnit 9.5.0 by Sebastian Bergmann and contributors.
になってた。
さらに追跡を進めているが・・・
fetchInner のデバッグ 残骸
protected function fetchInner()
{
var_dump('fetchInner 0');
if ($this->valid()) {
//var_dump('fetchInner 1');
$innerV = $this->inner->current();
//var_dump('fetchInner 2');
////var_dump(['iv'=>$innerV]);
$innerK = $this->inner->key();
//var_dump('fetchInner 3');
////var_dump(['ik'=>$innerK]);
var_dump($this->valueJoinSelector);
////var_dump(['ov'=>$this->outerV]);
////var_dump(['ok'=>$this->outerK]);
$this->v = $this->valueJoinSelector->select(
$this->outerV, $innerV,
$this->outerK, $innerK
);
var_dump($this->keyJoinSelector);
var_dump(['v'=>$this->v]);
var_dump('fetchInner 4');
$this->k = $this->keyJoinSelector->select(
$this->outerV, $innerV,
$this->outerK, $innerK
);
var_dump(['k'=>$this->k]);
var_dump('fetchInner 5');
}
var_dump('fetchInner 6');
}
valueJoinSelector・keyJoinSelector の 実体は Ginq\JoinSelector\DelegateJoinSelector で、
その実装は以下の通り
public function select($v0, $v1, $k0, $k1)
{
var_dump('DelegateJoinSelector select');
//var_dump(['func'=>$this->func]);
$f = $this->func;
//return $f($v0, $v1, $k0, $k1); //<- オリジナル
$rv = $f($v0, $v1, $k0, $k1); // <- ここで落ちている。Delegation できてない?
var_dump('DelegateJoinSelector selected');
var_dump($rv);
return $rv;
}
今日はここでギブアップ。
代替手段があれば置き換える、かな・・・
[補足]
PHP7.3 では期待通りに動作していた
PHP7.4 での SPL の ArrayObject 関連の変更による影響か・・・
refs
デバッグ環境を自分も整えてみている
docker-compose up -d
docker-compose exec php ash
/work # composer install
/work # vendor/bin/phpunit
でテストを動かせるようになっていると思う。
PHPUnit を 5 系から 7 系に上げてある。
PHPUnit_Framework_TestCase
を TestCase
に置き換えればOK。
use PHPUnit\Framework\TestCase;
は必要。
9 まで上げておきたい。
issue をクローズしました。
あとは、PHP と PHPUnit のバージョンアップ対応をこちらで行いたいところ。
現象が再現するコードを、ある程度公開可能な状態にしてお渡しして調査していただいた結果、
アプリケーション側のコードに NULL に対して安全になっていない箇所があると特定いただきました。
そのため、本件アプリケーション側を修正します。
調査いただき、本当にありがとうございました。お手数おかけしてしまい申し訳なくも思っています。
代わりになるか、自信がないのですが、PHP と PHPUnit のバージョンアップ対応を行っておいて、
今後のメンテナンスに少し寄与できればと思います。少々お時間ください。