Gramer tabanlı ayrıştırma her türlü için, düzenli ifadeler genellikle korkunç bir çözümdür. (Aritmetik gibi) Hatta smple gramerler yuvalama var ve (özellikle) bu düzenli ifadeler sadece devrilmesine yuva üzerinde bulunuyor.
Neyse PHP token_get_all() function aracılığıyla PHP yorumlayıcı tarafından kullanılan aynı sözel çözümleyici erişim vererek sizin için çok, çok daha iyi bir çözüm sağlar. PHP kodu bir karakter akışı vermek ve bunu oldukça basit bir finite state machine ile basit ayrıştırma biraz yapabilirsiniz, hangi belirteçleri ("lexemeler") ayrıştırmak gerekir.
Bu programı (kendisi üzerinde dener yüzden test.php olarak çalıştırılır) çalıştırın. Eğer kolaylıkla o kolları görebilirsiniz böylece dosya kasıtlı kötü biçimlendirilir.
<?
define('CONST1', 'value' );
define (CONST2, 'value2');
define( 'CONST3', time());
define('define', 'define');
define("test", VALUE4);
define('const5', //
'weird declaration'
) ;
define('CONST7', 3.14);
define ( /* comment */ 'foo', 'bar');
$defn = 'blah';
define($defn, 'foo');
define( 'CONST4', define('CONST5', 6));
header('Content-Type: text/plain');
$defines = array();
$state = 0;
$key = '';
$value = '';
$file = file_get_contents('test.php');
$tokens = token_get_all($file);
$token = reset($tokens);
while ($token) {
// dump($state, $token);
if (is_array($token)) {
if ($token[0] == T_WHITESPACE || $token[0] == T_COMMENT || $token[0] == T_DOC_COMMENT) {
// do nothing
} else if ($token[0] == T_STRING && strtolower($token[1]) == 'define') {
$state = 1;
} else if ($state == 2 && is_constant($token[0])) {
$key = $token[1];
$state = 3;
} else if ($state == 4 && is_constant($token[0])) {
$value = $token[1];
$state = 5;
}
} else {
$symbol = trim($token);
if ($symbol == '(' && $state == 1) {
$state = 2;
} else if ($symbol == ',' && $state == 3) {
$state = 4;
} else if ($symbol == ')' && $state == 5) {
$defines[strip($key)] = strip($value);
$state = 0;
}
}
$token = next($tokens);
}
foreach ($defines as $k => $v) {
echo "'$k' => '$v'\n";
}
function is_constant($token) {
return $token == T_CONSTANT_ENCAPSED_STRING || $token == T_STRING ||
$token == T_LNUMBER || $token == T_DNUMBER;
}
function dump($state, $token) {
if (is_array($token)) {
echo "$state: " . token_name($token[0]) . " [$token[1]] on line $token[2]\n";
} else {
echo "$state: Symbol '$token'\n";
}
}
function strip($value) {
return preg_replace('!^([\'"])(.*)\1$!', '$2', $value);
}
?>
Çıktı:
'CONST1' => 'value'
'CONST2' => 'value2'
'CONST3' => 'time'
'define' => 'define'
'test' => 'VALUE4'
'const5' => 'weird declaration'
'CONST7' => '3.14'
'foo' => 'bar'
'CONST5' => '6'
Bu temelde bir örüntü arar bir sonlu durum makinesi:
function name ('define')
open parenthesis
constant
comma
constant
close parenthesis
Bir PHP kaynak dosya ve davranır bir (isim, değer) çifti olarak iki sabitler sözcük akışında. Bunu yaparken (sonuçlarına göre) iç içe (define) ifadeleri kolları ve boşlukları ve yorumlar yanı sıra birden fazla hatları üzerinden çalışan sayar.
Note: Ben deliberatley fonksiyonlar ve değişkenler sabit isimleri veya değerlerdir zaman davayı görmezden ama istediğiniz gibi o bunu uzatabilirsiniz yaptık.
Ayrıca bu dizeleri gelince PHP oldukça bağışlayıcı olduğuna işaret değer. Onlar hiç tırnak ile tek tırnak, çift tırnak ya da (bazı durumlarda) ile ilan edilebilir. Bu sabit belirsiz bir referans referans olması (bamya tarafından işaret olarak) olabilir ve size ait chocie veren (zaten hiçbir garanti yolu), hangi bilmenin bir yolu var:
- Dizeleri (T_STRING) bu tarz almamak;
- Sabit zaten bu adla ilan edilmiştir görmesini ve değer yerine. Eğer ne de bir şey kesinlikle ne değeri, ne de bir sabit olup olmadığını kesin olarak söyleyemem böylece koşullu oluşturulan herhangi tanımlar işleyebilir ama diğer dosyaları adı olmuştur bilmek hiçbir yolu yok; veya
- Sadece bu sabitler (muhtemel) ve sadece dizeleri gibi onları tedavi olabilir ihtimali ile yaşayabilir.
Şahsen ben (1) sonra gitmek istiyorum (3).