Bir dosyadan Tüm İşlevini almak nasıl

4 Cevap php

Tamam, ben şimdi bir dosya üzerinden satır satır okuyorum. O başka bir XML belgesinde tanımlanan beri, dosyadaki her fonksiyonları adını biliyorum. Yani bu ne olmalıdır:

function function_name

Işlev_adı işlevin adıdır.

Ben zaten fonksiyon isimlerinin bir diziye koyduk bir XML belgesinden fonksiyon tanımları bütün olsun, ve ben php dosyasından sadece bu işlevleri kapmak gerekir. Sadece o bu işlevleri vardır ki ve o php dosyasını yeniden. Bir php dosyası ben bu işlevleri dışında şerit ve kullanıcı XML dosyasında belirtilen sadece fonksiyonları ile. Php dosyasını yeniden yazmak gerek daha, XML etiketinde tanımlanan olandan daha fazla işlevleri vardır eğer, söylemektir.

Yani, yüz ikilem çizgi ile bir fonksiyon okuma hattının END nasıl belirleneceği ve ben fonksiyonları içlerinde fonksiyonlara sahip olabilir farkında değilim. Yani içlerinde işlevleri kaldırmak istemiyorum. Bağımsız ve sadece fonksiyonlar ekteki XML dosyası içinde tanımlı değildir. Bunun nasıl herhangi bir fikir?

Tamam, ben şimdi şu işlevini kullanarak ediyorum:

//!!! - 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;
}

Tamam, bu php dosyaların içeriği alır böylece:

<?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();
}

?>

ve bunu gibi pek değiştirir:

<?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





?>

Gördüğünüz gibi buradan şeyler bir sürü aldı. Ve dirsek eksik son kapanış ... yapmam gereken tüm fonksiyon function module_testing Burada olup olmadığını kontrol edin ve tüm işlevini kapmak ve aynı dosyaya yazma. Yeterince basit görünüyor, ama WoW, bu IMO sadece bu küçük bir şey için bazı önemli kodlama olduğunu ...

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??

4 Cevap

Tamam, beyler, ben gayet Bunu düzeltmek başardı, ve kendi üzerinde ve burada mükemmel bir çözümdür. Ben bu ile yardım için teşekkür etmek istiyorum. Teşekkürler, çocuklar kadar burada bana yardımcı ötesine gitti. Ama bu tokenizer fonksiyonlarını kullanmadan basit bir çözüm olacağını biliyordu. Belki siz bana her işlevin adını zorunda olduğunu unutmuş? Her durumda, yine sayesinde, ancak bu belirteç işlevleri için gerekli olmayacaktır.

Şerefe.

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

Kullanıcı daha bir işlev içinde bir fonksiyonu varsa bunu tanımlamak zorunda kalacak, böylece ve bu başka türlü, işlevi düzgün çalışmaz, onu yapacaktır. Bu fonksiyonlar sınırsız miktarda olabilir beri Yani bu, gerçekten benim için büyük bir anlaşma değildir, ve daha iyi her işlev, kendisi için bir fonksiyon olduğunu uygun olacaktır.

Muhtemelen PHP dizgeciklerini denemek istiyorum.

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

Harici bir komut:

<?php

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

?>

Sarfraz belirtilen PHP tokenizer Eğer burada bahsettiğimiz ötesinde yeniden kod bir sürü yapıyor olacak konum, özellikle iyi bir fikirdir.

Ancak, bu durumda ihtiyacınız olmaz yeteri kadar basit olabilir.

Bir php fonksiyonu, iyi oluşmuş eğer, sahip olmalıdır:

function funcname($arg1,...,$argn) gibi görünüyor 1) Bir "kafa",. Muhtemelen bu bulmak ve bir regex ile bu çekin.

2) baş, eşleşen kıvırcık parantezler içinde dahil olan kafa sonra her şeyi oluşur gidiyor bir "beden", ardından. Yani, onları maç için nasıl anlamaya var. Bunu yapmanın bir yolu, bir $curlyBraceDepth değişkeni belirtmek olacaktır. 0 azından başlatın ve sonra fonksiyonun gövdesini açar küme ayracı ile başlayan, bir anda kod bir karakter üzerinden yürümek. Bir açılış ayracı karşılaşma her zaman, artım $curlyBraceDepth. Eğer bir kapatma ayracı karşılaşma her zaman, bunu azaltmak. (Geri derinlikte 0 olduğunuzda, örneğin) $curlyBraceDepth < 1, sen işlevi vücuda yürürken bitirecek zaman. Her bir karakteri kontrol geçiyor yaparken, size bir dizi okuduğunuz her karakter biriken olmak istiyorum, ya olacak ya sen zaten başlangıç ​​ve bitiş konumunu işaretleme, her bellekte bir dizesinde bu var ise daha sonra çekin.

Özellikle yaygın değil, ama kesinlikle hukuki ve olası php - - işlevlerden herhangi dizge içinde karakter olarak eşsiz kaşlı ayraçları işleme eğer o zaman da koşullu kod eklemek zorunda gidiyoruz: Şimdi, büyük bir ihtar burada var ayraç dizeleri ayrıştırmak. Eğer makul bunu bir köşe vaka olarak endişe ediyorsanız, hem de bu işlemek için kendi kod yazmak olsa da, Simgeleştirici muhtemelen gitmek için sağlam bir yoldur.

Ama sen yine de jeton, üzerinden tarama gibi ben yukarıda verdiğim algoritması gibi bir şey kullanarak olurdu - belirteçleri kafasını simgeleyen bulmak, sıralamak gövdesini içeren belirteçleri aracılığıyla, senin korse derinlik takip etmek T_CURLY_OPEN ve T_CURLY_CLOSE sayma , gitmek gibi simgeleri biriken ve sıfır ayracı derinliğe ulaştıklarında onları birleştirerek.

UPDATE (using Tokenizer)

token_get_all sözdizimsel önemli PHP belirteçleri kaynağının bireysel karakterleri koymasında ilgilenir. Burada hızlı bir örnek. Kullanıcının biz PHP kaynağı aşağıdaki dize var diyelim:

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

Ve biz bunu koşuyoruz token_get_all:

$tokens = token_get_all($s);

Eğer bu konuda bir print_r yaparsanız, burada (bazı inlined yorumlarla) görürsünüz ne:

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
        )

)

Dizideki girdilerden bazıları (düşündüğümden daha bu kolaylaştırır aslında parantez ve parantez,) karakter değişmezdir dikkat edin. Diğerleri 0 dizin bir "belirteç numarası" ve 1 dizin belirteç değişmezi (2 dizin '1 'değeri nedir hiçbir fikri) ihtiva eden, diziler vardır. Gerçekten, jeton sayısı değerlendiren bir PHP sabiti - - sen "belirteç adı" isterseniz token_name fonksiyonu yararlanabilirler. Örneğin, sayı 367 aşina ilk belirteç, adı ve PHP sürekli T_OPEN_TAG ile anılır.

Eğer B dosya dosya A fonksiyonunun kaynağını 'tek' kopyalamak için bu kullanmak istedim, $tokens = token_get_all(file_get_contents('file_A')) yapmak, ve o fonksiyonun başlangıcını ifade değişmez belirteçleri dizisi için arama yapabilir - - Bizim durumumuzda, T_FUNCTION, T_WHITESPACE, ve 'bir' eşit olan bir T_STRING. Yani:

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;

, 1 bir girinti düzeyinde fonksiyonu vücut için açılış küme ayracı da başlayacak kaşlı ayraç belirteçleri izlemek, derinlik takip ve jetonları birikir: Bu noktada, ben daha önce açıklanan ne yapardım:

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

A function will - as far as I know - always be included in those brackets: {}. So your job is to scan the phpfile for the start of the function - you said that's not the problem - and then you have to scan so far that all opened {got closed.

Ama ne var bir fonksiyonu veya if-fıkra ya da bu parantez kullanıyor sizin işlevi başka bir şey? Bir $counter, her { ve her } için aşağı yukarı hangi sayar impement zorunda yönetmek için. counter = zero işlevin sonuna varılırsa.

Example: Your function:

//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

Sayaç size kod derinliğini söyler. Derinliği = 0 fonksiyonu sona erdi eğer.

Analiz: Siz phpfile sonra başlayan, depolanan karakter bir $ dizi var function f_unimportant($args) {.

$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.

ve function f_unimportant($args) { lutfen silmek unutmayın (dolar uzunluğu sayılmaz!)