PHP'de bir dil yapısı ile "yerleşik" bir işlev arasındaki fark nedir?


92

Bunu biliyorum include, isset, require, print, echo, ve bazıları fonksiyonları ama dil yapıları değildir.

Bu dil yapılarının bazıları parantez gerektirir, bazıları ise yoktur.

require 'file.php';
isset($x);

Bazılarının dönüş değeri vardır, bazılarının yoktur.

print 'foo'; //1
echo  'foo'; //no return value

Öyleyse bir dil yapısı ile yerleşik bir işlev arasındaki fark nedir?

Yanıtlar:


132

(Bu istediğimden daha uzun; lütfen bana katlanın.)

Çoğu dil, "sözdizimi" adı verilen bir şeyden oluşur: dil, birkaç iyi tanımlanmış anahtar sözcükten oluşur ve bu dilde oluşturabileceğiniz tüm ifadeler bu sözdiziminden oluşturulur.

Örneğin, girdi olarak yalnızca tek basamaklı tam sayıları alan ve işlem sırasını tamamen yok sayan basit bir dört işlevli aritmetik "diliniz" olduğunu varsayalım (size bunun basit bir dil olduğunu söylemiştim). Bu dil sözdizimi ile tanımlanabilir:

// The | means "or" and the := represents definition
$expression := $number | $expression $operator $expression
$number := 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
$operator := + | - | * | /

Bu üç kuraldan, istediğiniz sayıda tek basamaklı giriş aritmetik ifadeleri oluşturabilirsiniz. Daha sonra, bu sözdizimi için bir ayrıştırıcı yazabilirsiniz herhangi bir geçerli bileşen tipe girdi (aşağı kırılır $expression, $numberya $operatorsonuçla) ve fırsatlar. Örneğin, ifade 3 + 4 * 5aşağıdaki gibi bölünebilir:

// Parentheses used for ease of explanation; they have no true syntactical meaning
$expression = 3 + 4 * 5
            = $expression $operator (4 * 5) // Expand into $exp $op $exp
            = $number $operator $expression // Rewrite: $exp -> $num
            = $number $operator $expression $operator $expression // Expand again
            = $number $operator $number $operator $number // Rewrite again

Şimdi, orijinal ifade için tanımlı dilimizde tamamen ayrıştırılmış bir sözdizimimiz var. Bunu elde ettikten sonra, tüm kombinasyonlarının sonuçlarını bulmak için bir ayrıştırıcı yazabilir $number $operator $numberve yalnızca bir tane kaldığımızda bir sonuç çıkarabiliriz $number.

$expressionOrijinal ifademizin son ayrıştırılmış versiyonunda hiçbir yapı kalmadığına dikkat edin. Çünkü $expressiondilimizde her zaman başka şeylerin bir kombinasyonuna indirgenebilir.

PHP aşağı yukarı aynıdır: dil yapıları, $numberveya $operator. Bunlar diğer dil yapılarının içine indirgenemez ; bunun yerine, dilin oluşturulduğu temel birimlerdir. Fonksiyonlar ve dil yapıları arasındaki temel fark şudur: ayrıştırıcı, doğrudan dil yapılarıyla ilgilenir. Fonksiyonları dil yapılarına dönüştürür.

Dil yapılarının parantez gerektirip gerektirmeyebileceğinin nedeni ve bazılarının dönüş değerlerine sahip olmasının, diğerlerinin ise tamamen PHP çözümleyici uygulamasının belirli teknik ayrıntılarına bağlı olmaması. Ayrıştırıcının nasıl çalıştığı konusunda o kadar bilgili değilim, bu yüzden bu soruları özel olarak ele alamam, ancak bir an için bununla başlayan bir dil hayal edin:

$expression := ($expression) | ...

Etkili bir şekilde, bu dil bulduğu ifadeleri almakta ve çevresindeki parantezlerden kurtulmakta özgürdür. PHP (ve burada saf tahmin kullanıyorum) dil yapıları için benzer bir şey kullanabilir: çözümlenmeden önce print("Hello")kısaltılabilir print "Hello"veya tam tersi olabilir (dil tanımları parantez ekleyebilir ve onlardan kurtulabilir).

Bu, echoveya gibi dil yapılarını neden yeniden tanımlayamadığınızın köküdür print: bunlar ayrıştırıcıya etkin bir şekilde kodlanırken, işlevler bir dizi dil yapısına eşlenir ve ayrıştırıcı, bu eşlemeyi derleme veya çalışma zamanında değiştirmenize izin verir. kendi dil yapılarınızı veya ifadelerinizi değiştirin.

Günün sonunda, yapılar ve ifadeler arasındaki iç fark şudur: dil yapıları çözümleyici tarafından anlaşılır ve ele alınır. Yerleşik işlevler, dil tarafından sağlanırken, ayrıştırmadan önce bir dizi dil yapısına eşlenir ve basitleştirilir.

Daha fazla bilgi:

  • Backus-Naur formu , resmi dilleri tanımlamak için kullanılan sözdizimi (yacc bu formu kullanır)

Düzenleme: Diğer cevaplardan bazılarını okuyarak, insanlar iyi puanlar alıyor. Onların arasında:

  • Yerleşik bir dil çağırmak bir işlevden daha hızlıdır. Bu, çok az da olsa doğrudur, çünkü PHP yorumlayıcısının bu işlevi ayrıştırmadan önce kendi dil yerleşik eşdeğerlerine eşlemesi gerekmez. Modern bir makinede ise fark oldukça önemsizdir.
  • Yerleşik bir dil, hata denetimini atlar. Bu, her yerleşik için PHP'nin dahili uygulamasına bağlı olarak doğru olabilir veya olmayabilir. Çoğu zaman, işlevlerin daha gelişmiş hata denetimine ve yerleşiklerin sahip olmadığı diğer işlevlere sahip olacağı kesinlikle doğrudur.
  • Dil yapıları, işlev geri çağırmaları olarak kullanılamaz. Bu doğrudur, çünkü bir yapı bir işlev değildir . Ayrı varlıklardır. Bir yerleşiği kodladığınızda, bağımsız değişkenler alan bir işlevi kodlamazsınız - yerleşiğin sözdizimi doğrudan ayrıştırıcı tarafından işlenir ve bir işlevden ziyade yerleşik olarak tanınır. (Birinci sınıf işlevlere sahip dilleri düşünürseniz, bunu anlamak daha kolay olabilir: etkili bir şekilde, işlevleri nesneler olarak geçirebilirsiniz. Bunu yerleşiklerle yapamazsınız.)

2
Sadece PHP'ye değil, birçok dile uygulanabilecek kadar açık uçlu harika bir cevap. Teşekkür ederim!
Levi Botelho

15

Dil yapıları dilin kendisi tarafından sağlanır ("if", "while", ... gibi talimatlar gibi); dolayısıyla onların adı.

Bunun bir sonucu, önceden tanımlanmış veya kullanıcı tanımlı işlevlerden daha hızlı çağrılmalarıdır (veya bu yüzden birkaç kez duydum / okudum)

Nasıl yapıldığına dair hiçbir fikrim yok, ancak yapabilecekleri bir şey (doğrudan dile entegre edilmeleri nedeniyle) bir tür hata işleme mekanizmasını "baypas etmek". Örneğin, isset () herhangi bir uyarı, uyarı veya hataya neden olmadan var olmayan değişkenlerle kullanılabilir.

function test($param) {}
if (test($a)) {
    // Notice: Undefined variable: a
}

if (isset($b)) {
    // No notice
}

* Tüm dillerin yapıları için geçerli olmadığını unutmayın.

Fonksiyonlar ve dil yapıları arasındaki diğer bir fark, bunlardan bazılarının bir anahtar kelime gibi parantez olmadan çağrılabilmesidir.

Örneğin :

echo 'test'; // language construct => OK

function my_function($param) {}
my_function 'test'; // function => Parse error: syntax error, unexpected T_CONSTANT_ENCAPSED_STRING

Burada da, tüm dil yapıları için durum böyle değil.

Sanırım bir dil yapısını "devre dışı bırakmanın" kesinlikle bir yolu yoktur, çünkü o dilin kendisinin bir parçasıdır. Öte yandan, birçok "yerleşik" PHP işlevi gerçekten yerleşik değildir çünkü bunlar her zaman etkin olacak şekilde uzantılar tarafından sağlanır (ancak hepsi değil)

Diğer bir fark, dil yapılarının "işlev işaretçileri" olarak kullanılamamasıdır (örneğin, geri aramaları kastediyorum):

$a = array(10, 20);

function test($param) {echo $param . '<br />';}
array_map('test', $a);  // OK (function)

array_map('echo', $a);  // Warning: array_map() expects parameter 1 to be a valid callback, function 'echo' not found or invalid function name

Şu anda aklıma gelen başka bir fikrim yok ... ve PHP'nin içindekiler hakkında pek bir bilgim yok ... O yüzden şimdi öyle olacak ^^

Burada çok fazla yanıt alamazsanız, belki bunu , birçok PHP çekirdek geliştiricisinin olduğu posta listesi dahililerine (bkz. Http://www.php.net/mailing-lists.php ) sorabilirsiniz ; Muhtemelen bu şeyleri bilenler onlar ^^

(Ve diğer cevaplarla gerçekten ilgileniyorum, btw ^^)

Referans olarak: PHP'deki anahtar sözcüklerin ve dil yapılarının listesi


Değişkeni referans alarak bir bildirim oluşturmadan set olmayan bir değişkeni kabul eden bir işleve sahip olabilirsiniz. Bu, isset () gibi dil yapıları ile sınırlı değildir.
Tom Haigh

Oh, bunu düşünmedim :-( Teşekkürler!
Pascal MARTIN

4

Kodu gözden geçirdikten sonra, php'nin bir yacc dosyasındaki bazı ifadeleri ayrıştırdığını buldum. Yani bunlar özel durumlardır.

(bkz. Zend / zend_language_parser.y)

Bunun dışında başka farklılıklar olduğunu düşünmüyorum.


1

Sen olabilir yerleşik üzerine yazılmış fonksiyonları . Anahtar kelimeler sonsuzdur.


Bu yerleşik bir işlev değil. APD (Advanced PHP Debugger) uzantısında tanımlanmıştır.
Ionuț G. Stan

işlevlerin geçersiz kılınmasıyla ilgili olarak, runkit uzantısında bir ganimet elde edebilirsiniz (bu da çekirdek değil, bir uzantıdır, dolayısıyla OP'ye yanıt vermez, yalnızca bu yanıta yanıt verir); gerçekten güçlü ve APD'den daha yeni (ve bir süre önce bazı insanların pecl.php.net'te gösterilmese bile hala üzerinde çalıştığını duyduğuma inanıyorum)
Pascal MARTIN
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.