成人精品一区二区三区中文字幕-成人精品一区二区三区-成人精品一级毛片-成人精品亚洲-日本在线视频一区二区-日本在线视频免费

導(dǎo)航首頁 ? 技術(shù)教程 ? PHP基于閉包思想實(shí)現(xiàn)的BT(torrent)文件解析工具實(shí)例詳解
全站頭部文字 我要出現(xiàn)在這里
PHP基于閉包思想實(shí)現(xiàn)的BT(torrent)文件解析工具實(shí)例詳解 823 2023-12-08   

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

PHP對(duì)靜態(tài)詞法域的支持有點(diǎn)奇怪,內(nèi)部匿名函數(shù)必須在參數(shù)列表后面加上use關(guān)鍵字,顯式的說明想要使用哪些外層函數(shù)的局部變量。

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

我本來是想這樣的。但是不行,會(huì)在第7行調(diào)用$func的時(shí)候報(bào)錯(cuò)。

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

反復(fù)試驗(yàn)后發(fā)覺,外部的匿名函數(shù)應(yīng)該通過引用傳值傳給內(nèi)部,否則是不行的:

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

像上面這樣寫就對(duì)了。

下面是另一種方法:

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

不過,這段代碼有點(diǎn)小錯(cuò)誤。編譯雖然沒錯(cuò),但是$foo函數(shù)每次返回的都是4.

也就是use關(guān)鍵字看上去像是支持靜態(tài)詞法域的,在這個(gè)例子上,它只是對(duì)外層函數(shù)使用的變量作了一個(gè)簡(jiǎn)單拷貝。

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

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

這樣才正確。

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

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

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

這樣不會(huì)像前一個(gè)例子那樣失去了遞歸調(diào)用的能力。

雖然這是一個(gè)類,但是只不過是在手動(dòng)實(shí)現(xiàn)那些支持閉包和靜態(tài)詞法域的語言中,編譯器自動(dòng)實(shí)現(xiàn)的動(dòng)作。

其實(shí)今天早上,我本來準(zhǔn)備用類scheme的風(fēng)格寫一個(gè)解析器的。可能稍微晚點(diǎn)吧。scheme風(fēng)格的函數(shù)式編程是這樣的:

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);

它不是很依賴靜態(tài)詞法域,雖然scheme對(duì)靜態(tài)詞法域的支持還是很不錯(cuò)的。它主要還是利用了first-class-function。當(dāng)然,這也是一種典型的閉包。

我實(shí)現(xiàn)的torrent解析工具的代碼如下:

<?php
$file_name = '1.torrent';
$file = fopen($file_name,'r');
$nil = new Parser($file);//構(gòu)造解析器
$nil = $nil();//進(jìn)行解析
$pos = ftell($file);
echo '讀取到文件位置'.sprintf('0x%08X',$pos)."rn";
fseek($file,0,SEEK_END);
echo '還剩下'.(ftell($file) - $pos).'字節(jié)未讀取'."rn";
if(!feof($file))
{
  echo '文件還未結(jié)束,再讀一個(gè)字符:';
  $ch = fgetc($file);
  if(is_string($ch) && ereg('w',$ch))
  {
    echo $ch."rn";
  }
  else
  {
    printf('0x%02X',$ch);
    echo "rn";
  }
  echo '現(xiàn)在的文件位置是'.sprintf('0x%08X',ftell($file))."rn";
  echo '文件'.(feof($file)?'已結(jié)束':'還未結(jié)束')."rn";
}
fclose($file);//解析器后面不再工作了,此時(shí)可以釋放文件指針了。
$info = @$nil['value'][0]['info'];
if(!$info)
{
  echo '這是一個(gè)有效的B-Encoding文件,但它不是一個(gè)有效的種子文件';
  exit();
}
$name = $info['name.utf-8'] ?$info['name.utf-8']:$info['name'];
if(!$name)
{
  echo '這是一個(gè)有效的B-Encoding文件,但它不是一個(gè)有效的種子文件';
  exit();
}
echo $name."rn";
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."個(gè)文件不含目錄rn";
      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 "rn";
  }
}
else
{
  echo "僅有一個(gè)文件rn";
}
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 '解析數(shù)字時(shí)遇到錯(cuò)誤',"rn";
            echo '在i和e之間不應(yīng)該出現(xiàn)非數(shù)字字符'."rn";
            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();
        //這個(gè)$node變量作為字典對(duì)象準(zhǔn)備加入到$parent的孩子節(jié)點(diǎn)中去
        //$node['type'] = 'd';
        while('e' != ($tmp = $this($node)))
        {//每次給$node帶來一個(gè)新孩子
          $node = $tmp;
        }
        $child_count = count($node['value']);
        if($child_count % 2 != 0)
        {
          echo '解析結(jié)尾于';
          echo sprintf('0x%08X',ftell($this ->_file));
          echo '的字典時(shí)遇到錯(cuò)誤:'."rn";
          echo '字典的對(duì)象映射不匹配';
          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 '無效的字典結(jié)尾于';
            echo sprintf('0x%08X',ftell($this ->_file));
            echo ":rn";
            echo '解析[k => v]配對(duì)時(shí)遇到錯(cuò)誤,k應(yīng)為字符串';
            exit();
          }
          $product[$key] = $value;
        }
        /*
         * 思想是這樣的:子節(jié)點(diǎn)想要加入父節(jié)點(diǎn)時(shí),
         * 往父節(jié)點(diǎn)的value數(shù)組添加。
         * 當(dāng)父節(jié)點(diǎn)收集好所需的信息后,
         * 父節(jié)點(diǎn)自身再從它的value節(jié)點(diǎn)整合內(nèi)容
         * 對(duì)于字典和列表統(tǒng)一這樣處理會(huì)大大降低代碼量
         */
        $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函數(shù)包裹了$this ->_file變量
   */
  function read()
  {
    if(!feof($this ->_file))
    {
      return fgetc($this ->_file);
    }else{
      echo '意外的文件結(jié)束';
      exit();
    }
  }
  /*
   * unexpected_character函數(shù)接收2個(gè)參數(shù)
   * 它用于指明腳本在何處遇到了哪個(gè)不合法的字符,
   * 并在返回前終止腳本的運(yùn)行。
   */
  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."rn";
    echo "Analysing Process Teminated.";
    exit();
  }
}
?>

這里很有趣的是,明明我對(duì)文件調(diào)用了fseek($file,0,SEEK_END);移動(dòng)到文件末尾了,但是feof還是報(bào)告說文件沒有結(jié)束,并且fgetc返回一個(gè)0,而沒有報(bào)錯(cuò)。但是此時(shí)文件實(shí)際上已經(jīng)到末尾了。

更多關(guān)于PHP相關(guān)內(nèi)容感興趣的讀者可查看本站專題:《php curl用法總結(jié)》、《php字符串(string)用法總結(jié)》、《PHP數(shù)組(Array)操作技巧大全》、《php排序算法總結(jié)》、《PHP常用遍歷算法與技巧總結(jié)》、《PHP數(shù)據(jù)結(jié)構(gòu)與算法教程》、《php程序設(shè)計(jì)算法總結(jié)》、《PHP數(shù)學(xué)運(yùn)算技巧總結(jié)》及《PHP運(yùn)算與運(yùn)算符用法總結(jié)》、

希望本文所述對(duì)大家PHP程序設(shè)計(jì)有所幫助。


主站蜘蛛池模板: 浙江卫视节目表电视猫| 720lu在线观看| 儿子结婚请帖邀请函电子版| 小小少年电影简介| 吴彦姝演过的电视剧大全| 脚 vk| 一路向东电影| 成家立业演员表| 97理伦| 小妹电影| 《灿烂的季节》大结局| 电影白蛇传| 五行字库查询| 王尧演员| 新成长的烦恼| 抖音怎么开店卖东西| 《遇见你之后》电影在线观看| 难兄难弟 电视剧| 我爱五指山我爱万泉河| 康熙王朝50集免费观看投屏电视剧| 天地姻缘七仙女演员表| 邻家花美男 电视剧| 成品直播大全免费观看| 好一个中国大舞台简谱| 尸家重地演员表| 三年片观看免费完整版中文版| 小孩打屁股针视频| 国生小百合| 四查四看自我剖析材料| 卜算子咏梅拼音| 男女瑟瑟视频| 调音师结局剧情大解析| 李采潭和黑人50分钟| 贪玩的小水滴300字完整版| 西野翔电影| 许华升公个人资料身高多少| 全能住宅改造王| 烽火流金电视剧全集免费观看| 蜡笔小新日语| av电影网| 妈妈的朋友未删减版|

!!!站長(zhǎng)長(zhǎng)期在線接!!!

網(wǎng)站、小程序:定制開發(fā)/二次開發(fā)/仿制開發(fā)等

各種疑難雜癥解決/定制接口/定制采集等

站長(zhǎng)微信:lxwl520520

站長(zhǎng)QQ:1737366103