2017-07-04 11 views
7

私は非常に奇妙な問題に遭遇しました。可能性のあるバグを発見するために記録すると思いました。私は現在、受け入れ可能な回避策があります。オブジェクトプロパティにPHPクロージャを格納することで既知の副作用はありますか?

私のプロジェクトはphpseclibを使用してリモートサーバとのSSH接続とSFTP接続を行うPHPベースのデプロイメントツールです。 SSH2の拡張機能よりもこれで運が増えたので、今のところそれに固執することに決めました。私は、Dockerised Alpine 3.5環境の中でPHP 7.0.16を実行しています。実際の(ローカル)SSHサーバに接続するPHPUnit内の機能テストを実行しているときに問題が発生します。

送信用のファイルを準備するときに、一時的なコピーを作成するプロセスを経るため、文字列の検索と置換を使用してケースごとに変更を加えることができます。私は何かが少ないダイナミックたいので、私は日付がどのように見えるかを定義するには、クラス全体のクロージャを追加するだろうと思ったのにテストのために:

abstract class Base 
{ 
    // (other properties here) 
    protected $dateGenerator; 

    public function __construct(QueueState $queueState, BaseFetcher $fetcher) 
    { 
     $this->queueState = $queueState; 
     $this->fetcher = $fetcher; 

     // Sets a default date generator 
     $this->dateGenerator = function() { return date('r'); }; 
    } 
} 

ので、ここでの考え方は、閉鎖は「本物」ジェネレータであり、かつテスト環境では静的なものだけで置き換えることができます。

ので、ここでの問題の症状である - 通知がたくさん:

~ # ./phpunit test/functional/tests/Sftp --stop-on-error 
PHPUnit 6.2.2 by Sebastian Bergmann and contributors. 

...........              11/11 (100%) 

Time: 7.56 seconds, Memory: 6.00MB 

OK (11 tests, 17 assertions) 
PHP Notice: Connection closed prematurely in /root/vendor/phpseclib/phpseclib/phpseclib/Net/SSH2.php on line 3599 
PHP Notice: Connection closed prematurely in /root/vendor/phpseclib/phpseclib/phpseclib/Net/SSH2.php on line 3599 
PHP Notice: Connection closed prematurely in /root/vendor/phpseclib/phpseclib/phpseclib/Net/SSH2.php on line 3599 
PHP Notice: Connection closed prematurely in /root/vendor/phpseclib/phpseclib/phpseclib/Net/SSH2.php on line 3599 
PHP Notice: Connection closed prematurely in /root/vendor/phpseclib/phpseclib/phpseclib/Net/SSH2.php on line 3599 
PHP Notice: Connection closed prematurely in /root/vendor/phpseclib/phpseclib/phpseclib/Net/SSH2.php on line 3599 
PHP Notice: Connection closed prematurely in /root/vendor/phpseclib/phpseclib/phpseclib/Net/SSH2.php on line 3599 
PHP Notice: Connection closed prematurely in /root/vendor/phpseclib/phpseclib/phpseclib/Net/SSH2.php on line 3599 
PHP Notice: Connection closed prematurely in /root/vendor/phpseclib/phpseclib/phpseclib/Net/SSH2.php on line 3599 
PHP Notice: Connection closed prematurely in /root/vendor/phpseclib/phpseclib/phpseclib/Net/SSH2.php on line 3599 
PHP Notice: Connection closed prematurely in /root/vendor/phpseclib/phpseclib/phpseclib/Net/SSH2.php on line 3599 
PHP Notice: Connection closed prematurely in /root/vendor/phpseclib/phpseclib/phpseclib/Net/SSH2.php on line 3599 
PHP Notice: Connection closed prematurely in /root/vendor/phpseclib/phpseclib/phpseclib/Net/SSH2.php on line 3599 
PHP Notice: Connection closed prematurely in /root/vendor/phpseclib/phpseclib/phpseclib/Net/SSH2.php on line 3599 
PHP Notice: Connection closed prematurely in /root/vendor/phpseclib/phpseclib/phpseclib/Net/SSH2.php on line 3599 
PHP Notice: Connection closed prematurely in /root/vendor/phpseclib/phpseclib/phpseclib/Net/SSH2.php on line 3599 
PHP Notice: Connection closed prematurely in /root/vendor/phpseclib/phpseclib/phpseclib/Net/SSH2.php on line 3599 
PHP Notice: Connection closed prematurely in /root/vendor/phpseclib/phpseclib/phpseclib/Net/SSH2.php on line 3599 

$this->dateGeneratorが実際にどこにも使用されていないこと。さて、ここで奇妙である、私は空の閉鎖に置き換えることができ、そして私は再び通知を得る:

$this->dateGenerator = function() {}; 

しかし、私はそれをコメントアウトした場合、通知は消えます。

#$this->dateGenerator = function() {}; 

私はこれを中心に多くのことを試してきました。私は問題がctorにクロージャを格納しているのかどうか疑問に思ったので、空のクロージャをセッターに注入しようとしましたが、再び通知があります。

私はクラスのクロージャーを交換して、問題は再び消えます。それで私はそれを修正する方法ですが、通知の問題はphpseclibライブラリ、あるいは私が構築しているすべてのものの安定性について神経質にしています! PHP、Docker、PHPUnit、phpseclib、ssh、sshdを使用しているので、問題を引き起こす可能性のあることがたくさんあります。

phpseclibチケットリストでは、この通知は#1125#985に記載されていますが、ここでデモンストレーションしている明らかに無関係のプロパティではなく、両方とも特定の原因があるようです。

私はこれをどのように研究することができますか?現在私はクロージャーが気づいていない副作用があると理論化しています。私はデストラクタでクロージャをnullにしようとしましたが、それは「閉じた」必要がある場合に備えていましたが、これは通知を止めませんでした。それはそのfsockはない有効なリソースであるか、またはEOFマーカーに達したときに例外をスローsend_binary_packet()、から来ているよう

+0

私がClosuresについて知っている1つの問題は、いくつかのlibs/hacksを使わずに直列化/逆シリアル化できないということです。しかし、それは "閉鎖のシリアライゼーションは許可されていません"エラーをスローする必要があります –

+0

ええ、それは探検する価値があるかもしれない、@マイカル - ありがとう。 PHPUnitには、テスト間のリソースのシリアライゼーションに関するいくつかのオプションがあることがわかっています。だから、私の試してみる価値があるかもしれません。私はこれに関連してこれ以上問題を抱えていないので、ゆっくりと研究をすることができる時を待たなければなりません。 – halfer

答えて

1

phpseclib\Net\SSH2にエラーの行番号を検索した後、それは私には見えます。

このBaseクラスから継承したオブジェクトがどこで使用されているのかを調べて、それらで何が行われているのかを見ていきます。あなたのdateGeneratorは明示的には呼び出されないかもしれませんが、それを見て何らかの理由でそれが好きではないかもしれません。あなたのコードではないコードを掘り起こす必要があるかもしれません。:/

+0

あなたの考えをありがとう。私は7月以来、問題の再発はなかった(そして同じコードベースで作業している)。私はクロージャーをもう一度付け加えれば戻ってくるだろうと思うが、とにかく私の修正を好む。 'dateGenerator'がどのように(偶然に)使用されたかについて私が知っていた最良のアイデアは、PHPUnitによってテスト間で自動的に行われるシリアライゼーション/デシリアライゼーションです。 – halfer

関連する問題