2014-01-30 30 views
3

目标:在cmd中运行一个PHP文件,脚本循环x次并在每次迭代时检查用户是否输入了任何输入(stream_select()STDIN),如果是这样 - 暂停循环直到用户输入,然后打印出输入并继续迭代。为什么当cmd.exe失去焦点时,STDIN上的stream_select变为阻塞状态?

问题:只要cmd.exe窗口处于焦点状态,脚本就会完美运行 - 当我单击另一个窗口时,脚本在stream_select处暂停,直到I后才会继续,但cmd窗口重新聚焦并发送一些输入(一个简单的输入按键就可以做到这一点)。没有错误。

问题:为什么失去对cmd的关注会影响stream_select并阻止循环? ...有没有解决方法? (例如,可以检查当前cmd窗口是否在焦点?)

代码示例,在工作目录中使用cmd php script.php

<?php 
$loopCount = 20; 

while ($loopCount) { 

    $start = microtime(true); 

    echo 'check on "' . $loopCount . '"' . PHP_EOL; 

    $stream = fopen('php://stdin', 'r'); 

    $stream_array = array($stream); 
    $write = array(); 
    $except = array(); 

    if (stream_select($stream_array, $write, $except, 1, 0)) { 
     $input = trim(fgets($stream)); 
     if ($input) { 
      echo 'input was "' . $input . '"' . PHP_EOL; 
     } 
    }  

    fclose($stream); 

    echo $loopCount . ' in ' . (microtime(true) - $start) . PHP_EOL; 

    $loopCount--;  

} 

事情我都试过,没有运气:

  • 移动fopenfclose外循环
  • ignore_user_abort(1);
  • stream_set_blocking($stream, 0);
  • null0和较高两种tv_sectv_usec值参数stream_select()
  • 检查connection_aborted()connection_status()

环境:Windows 7,XAMPP for Windows中,PHP 5.4.19(CLI),Zend引擎V2.4.0

回答

-1

我认为这个问题是因为s​​tream_select()当流接收到EOL时,也会为STDIN返回1,这是我认为在cmd失去焦点时发生的情况。

http://www.php.net/manual/en/function.stream-select.php

特别

,流资源也准备在文件结束-,在这种情况下的fread()将返回一个零长度字符串

当焦点位于没有丢失并且没有输入,stream_select返回0,并且传入的$ read数组通过引用被清空。当焦点丢失或给​​定输入时,$ read数组保持不变,您需要从每个索引读取数据。

但是这让我们窗口的用户处于不利的境地,因为我们没有办法通过stream_get_(内容|行)或fread或fgets非阻塞地读取长度为零的字符串。既然我们不能失去焦点,并提供实际的数据,我相信我们必须等待这些缺陷之一得到固定区分:

https://bugs.php.net/bug.php?id=36030

https://bugs.php.net/bug.php?id=34972

我目前正在探索的一个选项,以防止通过win32 API失去焦点的窗口,但即使我的需要,这看起来不切实际。

下面是我用现在的解决办法...

https://gist.github.com/anonymous/80080060869f875e7214

相关问题