久久久久久久av_日韩在线中文_看一级毛片视频_日本精品二区_成人深夜福利视频_武道仙尊动漫在线观看

PHP基于閉包思想實現的BT(torrent)文件解析工具實例詳解

這篇文章主要介紹了PHP基于閉包思想實現的BT(torrent)文件解析工具,結合具體實例形式分析了php針對torrent文件的讀取與解析相關操作技巧,需要的朋友可以參考下

本文實例講述了PHP基于閉包思想實現的torrent文件解析工具。分享給大家供大家參考,具體如下:

PHP對靜態詞法域的支持有點奇怪,內部匿名函數必須在參數列表后面加上use關鍵字,顯式的說明想要使用哪些外層函數的局部變量。

function count_down($count)
{
  return $func = function()
    use($count,$func)
  {
    if(--$count > 0)
      $func();
    echo "wow\n";
  };
}
$foo = count_down(3);
$foo();

我本來是想這樣的。但是不行,會在第7行調用$func的時候報錯。

錯誤是Fatal error: Function name must be a string in - on line 7

反復試驗后發覺,外部的匿名函數應該通過引用傳值傳給內部,否則是不行的:

function count_down($count)
{
  return $foo = function()
    use(&$count,&$foo)
  {
    echo $count."\n";
    if(--$count > 0)
      $foo();
  };
}
$foo = count_down(4);
$foo();

像上面這樣寫就對了。

下面是另一種方法:

function count_down_again($count)
{
  return function()use($count)
  {
    printf("wow %d\n",$count);
    return --$count;
  };
}
$foo = count_down_again(5);
while($foo() >0);

不過,這段代碼有點小錯誤。編譯雖然沒錯,但是$foo函數每次返回的都是4.

也就是use關鍵字看上去像是支持靜態詞法域的,在這個例子上,它只是對外層函數使用的變量作了一個簡單拷貝。

讓我們稍微修改一下,把第3行的use($count)改為use(&$count):

function count_down_again($count)
{
  return function()use(&$count)
  {
    printf("wow %d\n",$count);
    return --$count;
  };
}
$foo = count_down_again(5);
while($foo() >0);

這樣才正確。

我個人使用的方式是基于類的,做成了類似下面的形式:

class Foo
{
  public function __invoke($count)
  {
    if($count > 0)
      $this($count - 1);
    echo "wow\n";
  }
}
$foo = new Foo();
$foo(4);

這樣做的行為也是正確的。

這樣不會像前一個例子那樣失去了遞歸調用的能力。

雖然這是一個類,但是只不過是在手動實現那些支持閉包和靜態詞法域的語言中,編譯器自動實現的動作。

其實今天早上,我本來準備用類scheme的風格寫一個解析器的。可能稍微晚點吧。scheme風格的函數式編程是這樣的:

function yet_another_count_down($func,$count)
{
  $func($count);
  if($count > 0)
    yet_another_count_down($func,$count - 1);
}
yet_another_count_down(function($var){echo $var."\n";},6);

它不是很依賴靜態詞法域,雖然scheme對靜態詞法域的支持還是很不錯的。它主要還是利用了first-class-function。當然,這也是一種典型的閉包。

我實現的torrent解析工具的代碼如下:

<?php
$file_name = '1.torrent';
$file = fopen($file_name,'r');
$nil = new Parser($file);//構造解析器
$nil = $nil();//進行解析
$pos = ftell($file);
echo '讀取到文件位置'.sprintf('0x%08X',$pos)."\r\n";
fseek($file,0,SEEK_END);
echo '還剩下'.(ftell($file) - $pos).'字節未讀取'."\r\n";
if(!feof($file))
{
  echo '文件還未結束,再讀一個字符:';
  $ch = fgetc($file);
  if(is_string($ch) && ereg('\w',$ch))
  {
    echo $ch."\r\n";
  }
  else
  {
    printf('0x%02X',$ch);
    echo "\r\n";
  }
  echo '現在的文件位置是'.sprintf('0x%08X',ftell($file))."\r\n";
  echo '文件'.(feof($file)?'已結束':'還未結束')."\r\n";
}
fclose($file);//解析器后面不再工作了,此時可以釋放文件指針了。
$info = @$nil['value'][0]['info'];
if(!$info)
{
  echo '這是一個有效的B-Encoding文件,但它不是一個有效的種子文件';
  exit();
}
$name = $info['name.utf-8'] ?$info['name.utf-8']:$info['name'];
if(!$name)
{
  echo '這是一個有效的B-Encoding文件,但它不是一個有效的種子文件';
  exit();
}
echo $name."\r\n";
if($info['files'])
{
  $index = 0;
  foreach($info['files'] as $f)
  {
    $index += 1;
    $path = $f['path.utf8'] ?$f['path.utf8'] :$f['path'];
    if(!$path)
    {
      echo '文件列表中的第'.$index."個文件不含目錄\r\n";
      continue;
    }
    if(0 === strpos($path[0],"_____padding_file_"))continue;
    $under_folder = false;
    foreach($path as $item)
    {
      if($under_folder)
      {
        echo '/';
      }else{
        $under_folder = true;
      }
      echo $item;
    }
    echo "\r\n";
  }
}
else
{
  echo "僅有一個文件\r\n";
}
class Parser
{
  private $_file;
  public function __construct($file)
  {
    $this ->_file = $file;
  }
  public function __invoke($parent = array())
  {
    $ch = $this ->read();
    switch($ch)
    {
    case 'i':
      {
        $n = $ch;
        while(($ch = $this ->read()) != 'e')
        {
          if(!is_numeric($ch))
          {
            echo '在';
            echo sprintf(
                '0x%08X',ftell($this ->_file));
            echo '解析數字時遇到錯誤',"\r\n";
            echo '在i和e之間不應該出現非數字字符'."\r\n";
            echo '意外的字符'.sprintf('0x%02X',$ch);
            exit();
          }
          else
          {
            $n .= $ch;
          }
        }
        $n += 0;
        $offset = count($parent['value']);
        $parent['value'][$offset] = $n;
        return $parent;
      }
      break;
    case 'd':
      {
        $node = array();
        //這個$node變量作為字典對象準備加入到$parent的孩子節點中去
        //$node['type'] = 'd';
        while('e' != ($tmp = $this($node)))
        {//每次給$node帶來一個新孩子
          $node = $tmp;
        }
        $child_count = count($node['value']);
        if($child_count % 2 != 0)
        {
          echo '解析結尾于';
          echo sprintf('0x%08X',ftell($this ->_file));
          echo '的字典時遇到錯誤:'."\r\n";
          echo '字典的對象映射不匹配';
          exit();
        }
        $product = array();
        for($i = 0; $i < $child_count; $i += 2)
        {
          $key = $node['value'][$i];
          $value = $node['value'][$i + 1];
          if(!is_string($key))
          {
            echo '無效的字典結尾于';
            echo sprintf('0x%08X',ftell($this ->_file));
            echo ":\r\n";
            echo '解析[k => v]配對時遇到錯誤,k應為字符串';
            exit();
          }
          $product[$key] = $value;
        }
        /*
         * 思想是這樣的:子節點想要加入父節點時,
         * 往父節點的value數組添加。
         * 當父節點收集好所需的信息后,
         * 父節點自身再從它的value節點整合內容
         * 對于字典和列表統一這樣處理會大大降低代碼量
         */
        $offset = count($parent['value']);
        $parent['value'][$offset] = $product;
        return $parent;
      }
      break;
    case 'l';
      {
        $node = array();
        while('e' != ($tmp = $this($node)))
        {
          $node = $tmp;
        }
        $offset = count($parent['value']);
        $parent['value'][$offset] = $node['value'];
        return $parent;
      }
      break;
    case 'e':
        return 'e';
      break;
    default:
      {
        if(!is_numeric($ch))
        {
          $this ->unexpected_character(
            ftell($this ->_file) - 1,$ch);
        }
        $n = $ch;
        while(($ch = $this ->read()) != ':')
        {
          $n .= $ch;
          if(!is_numeric($n))
          {
            unexpected_character(
              ftell($this ->_file) - 1,$ch);
          }
        }
        $n += 0;
        $str = '';
        for(; $n > 0; --$n)
        {
          $str .= $this ->read();
        }
        $offset = count($parent['value']);
        $parent['value'][$offset] = $str;
        return $parent;
      }
      break;
    }
  }
  /*
   * read函數包裹了$this ->_file變量
   */
  function read()
  {
    if(!feof($this ->_file))
    {
      return fgetc($this ->_file);
    }else{
      echo '意外的文件結束';
      exit();
    }
  }
  /*
   * unexpected_character函數接收2個參數
   * 它用于指明腳本在何處遇到了哪個不合法的字符,
   * 并在返回前終止腳本的運行。
   */
  function unexpected_character($pos,$val)
  {
    $hex_pos = sprintf("0x%08X",$pos);
    $hex_val = sprintf("0x%02X",$val);
    echo 'Unexpected Character At Position ';
    echo $hex_pos.' , Value '.$hex_val."\r\n";
    echo "Analysing Process Teminated.";
    exit();
  }
}
?>

【網站聲明】本站除付費源碼經過測試外,其他素材未做測試,不保證完整性,網站上部分源碼僅限學習交流,請勿用于商業用途。如損害你的權益請聯系客服QQ:2655101040 給予處理,謝謝支持。

相關文檔推薦

這篇文章主要介紹了PHP有序表查找之插值查找算法,簡單分析了插值查找算法的概念、原理并結合實例形式分析了php實現針對有序表插值查找的相關操作技巧,需要的朋友可以參考下
下面小編就為大家分享一篇ThinkPHP整合datatables實現服務端分頁的示例代碼,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
下面小編就為大家分享一篇PHP實現APP微信支付的實例講解,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
這篇文章主要介紹了PHP實現的多維數組排序算法,結合實例形式對比分析了php針對多維數組及帶有鍵名的多維數組進行排序相關操作技巧與注意事項,需要的朋友可以參考下
這篇文章主要為大家詳細介紹了php結合ajaxuploadfile實現無刷新文件上傳功能,具有一定的參考價值,感興趣的小伙伴們可以參考一下
本篇文章給大家詳細介紹了PHP開發接口使用RSA進行加密解密方法,對此有興趣的朋友可以學習下。
主站蜘蛛池模板: 91xxx在线观看 | 免费在线观看av网站 | 国产一区二区免费电影 | 日本一道本视频 | 欧美日韩国产在线观看 | 伊人久久综合 | 亚洲欧美日韩国产综合 | 夜夜草导航 | 日韩欧美三级电影在线观看 | 正在播放国产精品 | 欧美在线a | 日韩和的一区二在线 | 97久久久| 久久久久亚洲av毛片大全 | 中文字幕第49页 | 欧美日韩一区二区三区四区五区 | 一区二区三区视频在线观看 | 在线观看免费黄色片 | 亚洲欧洲一区 | 日韩精品一区二区三区在线观看 | 精品综合久久久 | 精品中文字幕在线观看 | 91av视频在线观看 | 综合久久综合久久 | 精品一区二区三 | 免费黄色大片 | 国产1区| 毛片.com | 久久天天躁狠狠躁夜夜躁2014 | 91成人| 国产精品久久国产精品 | 久久大| 国产激情精品一区二区三区 | 最新中文字幕一区 | 国产精品久久久久久久久久 | 米奇狠狠鲁| 免费观看日韩av | 欧美精品被 | 中文字幕第九页 | 国产精品电影网 | 国产一区二区三区在线 |