The example of the BT (torrent) File Parsing tool implemented by PHP Based on the closure idea is described in detail,

Source: Internet
Author: User

The example of the BT (torrent) File Parsing tool implemented by PHP Based on the closure idea is described in detail,

This article describes the torrent File Parsing tool implemented by PHP Based on the closure idea. We will share this with you for your reference. The details are as follows:

PHP's support for static lexical fields is a bit strange. Internal anonymous functions must add the use keyword behind the parameter list to explicitly describe the local variables of which outer functions are to be used.

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

I originally wanted. But no, an error will be reported when $ func is called in row 7th.

Error: Fatal error: Function name must be a string in-on line 7

After repeated tests, it was found that external anonymous functions should pass the reference value to internal functions, otherwise they will not work:

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

It's right to write it like above.

The following is another method:

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

However, this code is a small error. Although the compilation is correct, the $ foo function returns 4 at a time.

That is, the use keyword seems to support static lexical fields. In this example, it only copies the variables used by the external layer functions.

Let's change the use ($ count) of row 3rd to 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);

This is correct.

I personally use a class-based approach, which is similar to the following:

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

This is also correct.

In this way, the recursive call capability will not be lost as in the previous example.

Although this is a class, it is only an action automatically implemented by the compiler in languages that support closures and static lexical domains.

In fact, this morning I was going to write a parser in the scheme-like style. It may be a little late. Scheme-style functional programming is like this:

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

It does not rely heavily on static lexical fields, although scheme supports static lexical fields very well. It mainly uses the first-class-function. Of course, this is also a typical closure.

The code of my torrent parsing tool is as follows:

<? Php $ file_name = '1. torrent '; $ file = fopen ($ file_name, 'R'); $ nil = new Parser ($ file); // constructor $ nil = $ nil (); // parse $ pos = ftell ($ file); echo 'read to file location '. sprintf ('0x % 08x', $ pos ). "\ r \ n"; fseek ($ file, 0, SEEK_END); echo 'remaining '. (ftell ($ file)-$ pos ). 'bytes not readed '. "\ r \ n"; if (! Feof ($ file) {echo 'file is not over yet. Read another character:'; $ ch = fgetc ($ file); if (is_string ($ ch) & ereg ('\ W', $ ch) {echo $ ch. "\ r \ n";} else {printf ('0x % 02x', $ ch); echo "\ r \ n";} echo 'the current file location is '. sprintf ('0x % 08x', ftell ($ file )). "\ r \ n"; echo 'file '. (feof ($ file )? 'Ended ':' not finished '). "\ r \ n" ;}fclose ($ file); // The parser does not work anymore. In this case, the file pointer can be released. $ Info = @ $ nil ['value'] [0] ['info']; if (! $ Info) {echo 'This is a valid B-Encoding file, but it is not a valid seed file'; exit () ;}$ name = $ info ['name. UTF-8 ']? $ Info ['name. UTF-8 ']: $ info ['name']; if (! $ Name) {echo 'This is a valid B-Encoding file, but it is not a valid seed file'; 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 'nth in the file list '. $ index. "The files do not contain directories \ 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 "only one file \ r \ n";} class Parser {private $ _ file; public function _ construct ($ file) {$ this-> _ file = $ file;} public function _ invoke ($ pare Nt = array () {$ ch = $ this-> read (); switch ($ ch) {case 'I': {$ n = $ ch; while ($ ch = $ this-> read ())! = 'E') {if (! Is_numeric ($ ch) {echo 'in'; echo sprintf ('0x % 08x', ftell ($ this-> _ file )); echo 'encountered an error when parsing numbers ', "\ r \ n"; echo' should not contain non-numeric characters between I and e '. "\ r \ n"; echo 'unexpected characters '. 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 (); // This $ node variable is used as the dictionary object to be added to the $ parent child node. // $ node ['type'] = 'D'; while ('E '! = ($ Tmp = $ this ($ node) {// each time you bring a new child to $ node = $ tmp ;} $ child_count = count ($ node ['value']); if ($ child_count % 2! = 0) {echo 'is parsed at the end of'; echo sprintf ('0x % 08x', ftell ($ this-> _ file); echo 'dictionary encountered an error: '. "\ r \ n"; echo 'the dictionary object ing does not match '; 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 'the invalid dictionary ends with '; echo sprintf ('0x % 08x', ftell ($ this-> _ file); echo ": \ r \ n "; echo 'encountered an error when parsing [k => v] pairs. k should be a string'; exit ();} $ product [$ key] = $ value;}/** is like this: when a child node wants to add a parent node, * adds a value array to the parent node. * After the parent node collects the required information, * The parent node itself integrates content from its value node * unified dictionary and list processing will greatly reduce the amount of code */$ 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;}/** the read function wraps the $ this-> _ file variable */function read () {if (! Feof ($ this-> _ file) {return fgetc ($ this-> _ file);} else {echo 'unexpected file'; exit ();}} /** the unexpected_character function receives two parameters * this parameter indicates where the script encounters an invalid character, and * terminates the script before it returns. */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 () ;}}?>

It is interesting that I have called the filefseek($file,0,SEEK_END);After moving to the end of the file, the feof still reports that the file is not finished and fgetc returns a 0 value without an error. However, the file is actually at the end.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.