神秘的變數名特性

2022-07-26 05:00:17 字數 2369 閱讀 6288

在php語言中,變數都是儲存在雜湊表中,稱為變數符號表,其中變數名為雜湊表的鍵,變數名對應的容器zval的指標為雜湊表中的值。所有全域性變數放在一張主符號表中(也就是陣列$globals對應的雜湊表)。php語言有個特性,變數在命名時,$變數識別符號後不能以數字開頭。例如我們在以下**:

<?php

$111= "my";

會報如下錯誤:parse error: syntax error, unexpected t_lnumber, expecting t_variable or '$' in...

從錯誤的描敘來看,這是乙個語法錯誤,於是我們推論對變數名合法性的判斷應該是在編譯時的語法分析階段。

為了證明觀點,我們可以試著在執行階段定義乙個數字字元開頭的變數:

<?php

$a   = 111;

$$a = "my"; //以變數$a的值作為變數名

echo $$a;

var_dump($globals);

執行之後發現不報錯,並且在全域性符號表$globals中發現相關符號:

["a"]=>

int(111)

["111"]=>

string(2) "my"

這樣我們就定義了乙個全數字字元命名的變數,似乎違背了php的規則,但是確實做到了。

(讀者可以試著輸出$globals["111"]的值,雖然有值,但是結果卻為null,這個是php中乙個型別轉換的特性)

在這段**中,$$a = "my"這條語句具有多型性,只有當實際執行到這條語句的時候,我們才能確定變數名,php在語法分析階段無法知道這個變數名會是什麼,所以就不會報錯,在執行階段,php語言不判斷變數名的合法性,於是就產生了這樣乙個叛逆的變數。

知道了這個特性之後,馬上會想到乙個另外乙個特殊的變數:$this

在類的方法中,$this關鍵字用來指向當前類的物件例項,如果對$this進行賦值操作,會發生什麼事情?

執行**,報錯:

fatal error: cannot re-assign $this in...

php對$this變數做了一定保護措施,但是這個保護措施也不是完全的,我們利用前面的方法在執行期改變$this的值, 修改後的getname方法為:

然後執行**,發現能夠順利執行,$this的值變成了123, 由此可以判斷對$this關鍵字的保護也僅限與語法分析階段。

當$this的值變成123之後,按理說$this->_name肯定會報錯的,但是居然**能正常執行,這個確實很讓人覺得不可思議。於是推斷

$this->_name這樣的引用方式和一般的物件變數引用方式在有差異,我們繼續對getname做修改:

這段**中,$this和$b的值都等於123,但是$this->getage()可以順利執行,$b->getage()卻報錯:

fatal error: call to a member function getage() on a non-object...

這是乙個詭異的問題,於是可以推斷$this->getage()和$b->getage()在編譯之後對應的op handler肯定有所差異,於是檢視之。

通過vld檢視op的資訊

$this->getage()對應的為:

zend_init_method_call    res[  is_unused  ]         op1[  is_unused  ] op2[  is_const (8142027) 'getage' ]

$b->getage()在對應的為:

zend_init_method_call    res[  is_unused  ]         op1[  is_cv !0 ]      op2[ ,  is_const (8142039) 'getage' ]

雖然對應了同樣的op code,但是由於運算元的不同(前者不使用op1,後者使用op1, 且op1的值!0表示$b),同乙個op code對應同一類handler,然後根據運算元的型別確定到此類handler中的某乙個handler。

$this->getage()對應的handler處理為:zend_init_method_call_spec_unused_const_handler

$b->getage()    對應的handler處理為:zend_init_method_call_spec_cv_const_handler

這就是它們的差異了,在執行

$my = new person();

$name = $my->getname();

呼叫getname的時候,getname()的作用域(scope)已經被設定成$name物件中,語法分析的時候對於getname中$this->getage()這樣的呼叫時只是在當前作用域(scope)中呼叫getage()函式,不會理會$this的具體值,而在$b->getage()這樣的呼叫時,會關心$b所對應的值。

Oracle中的替換變數, 變數名, 變數名

替換變數 僅用於sql plus或者用於原理和sql plus相同的開發工具 臨時儲存值 利用它可以達到建立通用指令碼的目的 利用它可以達到和使用者互動,故在sql plus中又稱互動式命令 替換變數的格式式在變數名稱前加乙個 以便在執行sql命令時提示使用者輸入替換資料,然後按輸入資料執行sql命...

變數名命名

有些東西不明確寫出來就難以確定下來,個人寫 的命名風格一直沒有穩定下來,今天寫個筆記明確幾類主要的命名,希望可以逐步養成自己的程式設計風格。1.類名 型別名 t 每個單詞首字母大寫 例 t typename 2.列舉型別 反應型別的複數形式 例 enum colors 3.函式名 每個單詞首字母大寫...

變數名提公升

預解析的過程 的執行過程 程式在執行過程,會先將 讀取到記憶體中檢查,會將所有的宣告在此時進行標記。所謂的標記就是讓js直譯器直到有這個名字,後面在使用名字的時候,不會出現未定義的錯誤,這個標記就是提公升 宣告 名字的宣告,識別符號的宣告 變數名的提公升 函式的宣告 函式宣告與函式表示式有區別,函式...