2010-05-01 5 views
2

좋아, 이제 파일을 통해 한 줄씩 읽습니다. 파일의 각 함수 이름은 XML 문서의 다른 곳에서 정의되어 있으므로이 함수 이름을 알고 있습니다. 이것이 무엇이되어야 하는가 :파일에서 전체 기능을 얻는 방법

function function_name 

여기서 function_name은 함수의 이름입니다.

나는 모든 함수 정의를 이미 함수 이름의 배열에 넣은 XML 문서에서 얻었으며 PHP 함수에서 그 함수를 가져와야합니다. 그리고 php 파일을 재 구축하여 그 안에있는 함수 만 포함하도록하십시오. 즉, php 파일에 XML 태그에 정의 된 것보다 많은 함수가있는 경우 해당 함수를 제거하고 사용자가 XML 파일에 지정한 함수 만 사용하여 .php 파일을 다시 작성해야합니다.

필자가 직면 한 딜레마는 함수를 라인 단위로 읽는 방법을 결정하는 방법이며 함수가 함수를 가질 수 있다는 것을 알고 있습니다. 그래서 나는 그 안에있는 기능을 제거하고 싶지 않습니다. 독립형이며 함께 제공되는 XML 파일 내에서 정의되지 않은 기능들. 이 작업을 수행하는 방법에 대한 아이디어가 있습니까 ??

좋아, 이제 다음과 같은 기능을 사용하고 있습니다 :

//!!! - Used to grab the contents of all functions within a file with the functions array. 
function get_functions($source, $functions = array()) 
{ 
    global $txt; 

    if (!file_exists($source) || !is_readable($source)) 
     return ''; 

    $tokens = token_get_all(file_get_contents($source)); 

    foreach($functions as $funcName) 
    { 
     for($i=0,$z=count($tokens); $i<$z; $i++) 
     { 
      if (is_array($tokens[$i]) && $tokens[$i][0] == T_FUNCTION && is_array($tokens[$i+1]) && $tokens[$i+1][0] == T_WHITESPACE && is_array($tokens[$i+2]) && $tokens[$i+2][1] == $funcName) 
       break; 

      $accumulator = array(); 
      // collect tokens from function head through opening brace 
      while($tokens[$i] != '{' && ($i < $z)) { 
       $accumulator[] = is_array($tokens[$i]) ? $tokens[$i][1] : $tokens[$i]; 
       $i++; 
      } 
      if($i == $z) { 
       // handle error 
       fatal_error($txt['error_occurred'], false); 
      } else { 
       // note, accumulate, and position index past brace 
       $braceDepth = 1; 
       $accumulator[] = '{'; 
       $i++; 
      } 
      while($braceDepth > 0 && ($i < $z)) { 
       if(is_array($tokens[$i])) 
        $accumulator[] = $tokens[$i][1]; 
       else { 
        $accumulator[] = $tokens[i]; 
        if($tokens[$i] == '{') $braceDepth++; 
        else if($tokens[i] == '}') $braceDepth--; 
       } 
       $i++; 
      } 
      $functionSrc = implode(null,$accumulator); 
     } 
    } 

    return $functionSrc; 
} 

OK, 그것은이 PHP 파일 내용 소요 있도록 :

<?php 
function module_testing($params) 
{ 
    // Is it installed? 
    $test_param = !isset($params['test_param']) ? 'Testing Testing 1 2 3!' : $params['test_param']; 

    // Grab the params, if they exist. 
    if (is_array($params)) 
    {   
     echo $test_param; 
    } 
    // Throw an error. 
    else 
     module_error(); 
} 

?> 

을 등처럼 변경 :

<?php 

function module_testing($params) 

{ 

    // Is it installed? 

    $test_param isset$params'test_param' 'Testing Testing 1 2 3!' $params'test_param' 



    // Grab the params, if they exist. 

    if is_array$params 



     echo $test_param 



    // Throw an error. 

    else 

     module_error 





?> 

당신이 볼 수 있듯이, 여기에는 많은 것들이있었습니다. 마지막 닫기 괄호가 누락되었습니다. 여기에 함수가 있는지 확인하고 함수 전체를 잡고 같은 파일에 씁니다. 간단한데,하지만 와우, 당신은 아마도 PHP 토큰 화를 시도하려는

Or I could also check if a function is defined in here that isn't within the $functions array, if so, than just remove that function. Perhaps it's easier with this approach instead??

+0

얘들 아, 나는 이것을 스스로 해결했다. 아래 내 대답을 참조하십시오. 다시 고마워요 : – SoLoGHoST

답변

-1

좋아들 function f_unimportant($args) { aswell을 삭제하는 것을 잊지 마세요, 나는이 완벽하게 잘 해결하기 위해 관리하고, 내 자신에 여기에있다 완벽한 솔루션. 이 모든 것에 당신의 도움에 감사드립니다. 고마워, 너희들 여기서 나를 돕는 것 이상으로 갔어. 그러나 이것은 tokenizer 기능을 사용하지 않고도 간단한 해결책이라는 것을 알고있었습니다. 어쩌면 내가 각 기능의 이름을 잊어 버린 것일까? 어쨌든 다시 한번 감사 드리지만 토큰 기능은 필요하지 않습니다.

건배.

function remove_undefined_functions($source, $functions = array()) 
{ 
    if (!file_exists($source) || !is_readable($source)) 
     return ''; 

    $code = ''; 
    $removeStart = false; 

    $fp = fopen($source, 'rb'); 
    while (!feof($fp)) 
    { 
     $output = fgets($fp); 
     $funcStart = strpos(strtolower($output), 'function'); 

     if ($funcStart !== false) 
     { 
      foreach($functions as $funcName) 
      { 
       if (strpos($output, $funcName) !== false) 
       { 
        $code .= $output; 
        $removeStart = false; 
        break; 
       } 
       else 
        $removeStart = true; 
      } 
      continue; 
     } 
     else 
     { 
      if (substr($output, 0, 2) == '?>' || !$removeStart) 
       $code .= $output; 
     } 
    } 
    fclose($fp); 

    // Rewrite the file with the functions that are defined. 
    $fo = @fopen($source, 'wb'); 

    // Get rid of the extra lines... 
    @fwrite($fo, str_replace("\r\n", "\n", $code)); 

    fclose($fo); 
} 

그리고 함수의 내부 함수가 존재하는 경우, 사용자가 정의 할 것보다, 그렇지 않으면 기능이 제대로 작동하지 않도록이 그것을 만들 것입니다. 그래서 이것들은 무제한의 기능을 가질 수 있고, 각 기능이 스스로 기능하는 것이 더 낫기 때문에, 제게 큰 문제는 아닙니다.

1

... IMO 그냥 사소한 일에 대한 몇 가지 중요한 코드입니다.

<?php 

var_dump(token_get_all(file_get_contents('myscript.php'))); 

?> 
+0

OMG 어떻게 작동합니까? 나는 그것으로부터의 결과를 보았지만 그것이 나에게 의미가있는 경우라면 ....... – SoLoGHoST

+0

어떻게 그 방법을 사용하여 함수의 시작과 끝을 결정합니까 ?? 위의 var_dump를 보면 ...? 함수 이름은 "module_testing"이고 예, 거기에 표시되어 있습니다. 그러나 이것을 어떻게 사용합니까? 예제는 훌륭합니다. – SoLoGHoST

+0

@SoLoGHoST : 방금'var_dump'를 사용하여 예제를 보았습니다. 자세한 정보는'token_get_all' 문서를 참고하십시오 : http://php.net/manual/en/function.token-get-all.php – Sarfraz

4
Sarfraz 토크 나이 PHP의 언급

당신이했습니다 것 이상으로 재 작성 코드를 많이하고있을거야 경우 특히, 좋은 생각이다 : 외부 스크립트에서

http://www.php.net/manual/en/ref.tokenizer.php

언급했다.

그러나이 경우에는 필요하지 않을 정도로 간단 할 수 있습니다.

하는 PHP 함수가 잘 형성 않다면,이 있어야합니다 function funcname($arg1,...,$argn)처럼 보이는

1) A "머리",. 아마 이것을 찾아서 이것을 정규 표현식으로 풀 수 있습니다.

2) 머리에 이어 "몸체"는 일치하는 중괄호 쌍 안에 포함 된 머리 뒤의 모든 것으로 구성됩니다. 그래서, 당신은 그들을 일치시키는 방법을 찾아야합니다. 이를 수행하는 한 가지 방법은 $curlyBraceDepth 변수를 지정하는 것입니다. 0에서 시작한 다음 함수의 본문을 여는 중괄호로 시작하여 한 번에 한 문자 씩 코드를 살펴보십시오. 여는 중괄호를 발견 할 때마다 $curlyBraceDepth을 증분하십시오. 닫는 중괄호를 만날 때마다 그것을 줄입니다.$curlyBraceDepth < 1 (예 : 깊이 0으로 되돌아 왔을 때) 기능 본문을 걷는 것을 마쳤습니다. 각 문자를 검사하는 동안 배열에서 읽고있는 각 문자를 누적하거나 메모리에있는 문자열에이 문자열이 모두있는 경우 시작 및 끝 위치를 표시하면됩니다. 나중에 풀 수 있습니다.

여기에 큰주의 사항이 있습니다. 문자열 중 문자처럼 중괄호를 사용하지 않는 함수가있는 경우 (특히 일반적이지는 않지만 합법적이며 가능한 PHP 일 수 있음) - 또한 다음을 수행해야합니다. 별도의 토큰으로 문자열을 구문 분석하기위한 조건부 코드를 추가하십시오. 이것을 처리 할 수있는 자신 만의 코드를 작성할 수도 있지만, 모퉁이의 사례로 염려된다면 Tokenizer는 아마도 강력한 방법 일 것입니다.

그러나 내가 토큰을 스캔 할 때 위에 제시 한 알고리즘과 같은 것을 사용할 것입니다. 머리를 나타내는 토큰을 찾고 몸체를 구성하는 토큰을 정렬하고 트랙을 유지하기 위해 T_CURLY_OPEN 및 T_CURLY_CLOSE를 계산합니다 중괄호 깊이에 도달하면 토큰을 누적하고 연결구를 연결합니다. (토큰 화를 사용하여)

UPDATE는

token_get_all 구문 적으로 중요한 PHP 토큰에 소스의 개별 문자를 총괄을 담당. 여기에 간단한 예가 있습니다.

$s = '<?php function one() { return 1; }'; 

우리가 token_get_all를 통해 실행 :의 우리가 PHP 소스의 다음과 같은 문자열이 있다고 가정 해 봅시다

$tokens = token_get_all($s); 

이에 print_r을 할 경우, 여기에 일부 인라인으로 (볼거야 댓글) :

Array 
(
    [0] => Array 
     (
      [0] => 367  // token number (also known by constant T_OPEN_TAG) 
      [1] => <?php // token literal as found in source 
      [2] => 1   
     ) 

    [1] => Array 
     (
      [0] => 333  // token number (also known by constant T_FUNCTION) 
      [1] => function // token literal as found in source 
      [2] => 1  
     ) 

    [2] => Array 
     (
      [0] => 370  // token number (aka T_WHITESPACE) 
      [1] =>   // you can't see it, but it's there. :) 
      [2] => 1 
     ) 

    [3] => Array 
     (
      [0] => 307  // token number (aka T_STRING) 
      [1] => one  // hey, it's the name of our function 
      [2] => 1 
     ) 

    [4] => (    // literal token - open paren 
    [5] =>)    // literal token - close paren 
    [6] => Array 
     (
      [0] => 370 
      [1] => 
      [2] => 1 
     ) 

    [7] => { 
    [8] => Array 
     (
      [0] => 370 
      [1] => 
      [2] => 1 
     ) 

    [9] => Array 
     (
      [0] => 335 
      [1] => return 
      [2] => 1 
     ) 

    [10] => Array 
     (
      [0] => 370 
      [1] => 
      [2] => 1 
     ) 

    [11] => Array 
     (
      [0] => 305 
      [1] => 1 
      [2] => 1 
     ) 

    [12] => ; 
    [13] => Array 
     (
      [0] => 370 
      [1] => 
      [2] => 1 
     ) 

    [14] => } 
    [15] => Array 
     (
      [0] => 370 
      [1] => 
      [2] => 1 
     ) 

    [16] => Array 
     (
      [0] => 369 
      [1] => ?> 
      [2] => 1 
     ) 

) 

공지 배열의 항목 중 일부는 문자 리터럴 (괄호와 중괄호이다, 나는) 생각했던 것보다이 쉽게 사실이다. 다른 배열은 0 인덱스의 "토큰 번호"와 1 인덱스의 토큰 리터럴 (2 인덱스에서 '1'값이 무엇인지 알지 못함)을 포함하는 배열입니다. 토큰 번호로 평가되는 PHP 상수 인 "토큰 이름"을 원할 경우 token_name 함수를 사용할 수 있습니다. 예를 들어 익숙한 첫 번째 토큰 (숫자 367)은 이름과 PHP 상수 T_OPEN_TAG로 참조됩니다.

이 기능을 사용하여 파일 A에서 파일 B로 기능 소스 '원'을 복사하려는 경우 $tokens = token_get_all(file_get_contents('file_A'))을 수행 한 다음 해당 기능의 시작을 나타내는 리터럴 토큰 시퀀스를 검색 할 수 있습니다 우리의 경우, T_FUNCTION, T_WHITESPACE 및 '1'과 같은 T_STRING이 있습니다. 그래서 :

이 시점에서
for($i=0,$z=count($tokens); $i<$z; $i++) 
    if(is_array($tokens[$i]) 
    && $tokens[$i][0] == T_FUNCTION 
    && is_array($tokens[$i+1]) 
    && $tokens[$i+1][0] == T_WHITESPACE 
    && is_array($tokens[$i+2]) 
    && $tokens[$i+2][1] == 'one') 
     break; 

, 당신은 내가 설명 무엇을 할 거라고 이전 : 추적, 중괄호 토큰을 감시, 하나의 들여 쓰기 수준에서 함수의 본문에 대한 열기 중괄호에서 시작 깊이와 축적 토큰 : 함수가됩니다

$accumulator = array(); 
// collect tokens from function head through opening brace 
while($tokens[$i] != '{' && ($i < $z)) { 
    $accumulator[] = is_array($tokens[$i]) ? $tokens[$i][1] : $tokens[$i]; 
    $i++; 
} 
if($i == $z) { 
    // handle error 
} else { 
    // note, accumulate, and position index past brace 
    $braceDepth = 1; 
    $accumulator[] = '{'; 
    $i++; 
} 
while($braceDepth > 0 && ($i < $z)) { 
    if(is_array($tokens[$i])) 
     $accumulator[] = $tokens[$i][1]; 
    else { 
     $accumulator[] = $tokens[i]; 
     if($tokens[$i] == '{') $braceDepth++; 
     else if($tokens[i] == '}') $braceDepth--; 
    } 
} 
$functionSrc = implode(null,$accumulator); 
+0

고마워,하지만이 tokenizer 것은 이해가 안 돼, 내가 뭘 원하는지 복잡하게 보인다. 심지어 Sarfraz가 링크 된 링크에서 그것을 읽은 후에도. – SoLoGHoST

+0

조금 복잡하지만 실제로 그렇게 나쁘지는 않습니다. 몇 가지 예제 코드를 사용하여보다 긴밀하게 작동하는 방식을 설명하는 섹션을 추가했습니다. –

+0

와우, 고마워. bro :) – SoLoGHoST

0

- 내가 아는 한 - 항상 그 괄호에 포함 : {}. 그래서 phpfile을 스캔하여 함수의 시작 부분 (문제가 아니라고 말한 것)을 찾은 다음 지금까지 열려있는 모든 파일을 닫은 후 닫아야합니다.

하지만 함수 나 if 절 또는 함수에 대괄호를 사용하는 다른 것이 있으면 어떻게해야합니까?이를 처리하기 위해 $counter{에 대해 각각 카운트 업하고 각각 }에 대해 아래로 계산해야합니다. counter = zero의 경우 함수의 끝 부분에 도달합니다.

예 : 함수 :

//lots of functions 
function f_unimportant($args) { //Scan the first "{" after your f_unimportant 
           //and set $counter=1; 
if($args > '') {    //increase $counter by 1 
    //Do stuff 
}        //decrease $counter by 1 

echo $result; 

}        //decrease $counter by 1 
           //now $counter is zero and end of function is reached 

카운터는 당신에게 당신의 코드의 깊이를 알려줍니다. depth = 0 인 경우 함수가 종료되었습니다.

분석 : function f_unimportant($args) { 이후에 시작하는 phpfile이 저장된 $ 배열의 문자가 있습니다.

$counter = 1; 
$length = 0; //length of your function (to be able to delete it) 
foreach($array as $char) { 
    $length ++; 
    if($char == '{') { 
     $counter ++; 
    } 
    else if($char == '}') { 
     $counter --; 
    } 

    if($counter == 0) {break;} //leave foreach because end of function is reached 
} 
//now you just delete $length chars from your phpfile starting at the position 
//you already found out, where your function starts. 

하고, (이 $ 길이에 계산되지 않습니다!)

+0

이제 꽤 재미있는 개념입니다. – SoLoGHoST

+0

나는 그것이 작동 할 것이기를 바랍니다 :-) 나는 그것을 스스로 시도하지 않았습니다. 가장 중요한 것은 "abc foo {bar"와 같이 {또는}을 사용하는 함수 안에 문자열이 없다는 것입니다. 왜냐하면 모든 비트가 복잡해지기 때문입니다 ... – user329974

+0

그래, 무슨 뜻인지 알 겠어. 음, 아마도 tokenizer의 thingy는 유일한 보장 방법입니다 ... 고마워요 :) – SoLoGHoST

관련 문제