本文目錄一覽:
- 1、PHP的count(數組)和strlen(字符串)的內部實現。
- 2、PHP出現 unexpected T_STRING 錯誤,這裡的T_STRING什麼意思?
- 3、php語句,retval是什麼意思
- 4、PHP執行linux系統命令的常用函數使用說明
- 5、php的 strval和string有啥區別?
- 6、PHP怎麼從COM組件中獲取返回的字符串
PHP的count(數組)和strlen(字符串)的內部實現。
翻了下PHP內核的定義,大概心中也有了答案了
count()和strlen()都是O(1)的時間複雜度
試想一下如果strlen()需要O(N)的複雜度那未免也太慢了,字符串長度起來的話服務器不是要直接掛掉嗎
這兩個函數都是典型的空間換時間的做法
我們可以先看看zvalue的結構:
typedef union _zvalue_value {
long lval; /* long value */
double dval; /* double value */
struct {
char *val;
int len;
} str;
HashTable *ht; /* hash table value */
zend_object_value obj;
zend_ast *ast;
} zvalue_value;
這裡用的是一個聯合體,當變量類型是string類型的時候附加存儲多了一個len的整型變量,顯而易見需要取長度直接利用記錄值就可以了,自然就是O(1)
對於count()常用的參數類型應該為數組,對於繼承Countable的類暫不作討論
數組實現方式為Hashtable,直接看看他的結構吧
typedef struct _hashtable {
uint nTableSize; // hash Bucket的大小,最小為8,以2x增長。
uint nTableMask; // nTableSize-1 , 索引取值的優化
uint nNumOfElements; // hash Bucket中當前存在的元素個數,count()函數會直接返回此值
ulong nNextFreeElement; // 下一個數字索引的位置
Bucket *pInternalPointer; // 當前遍歷的指針(foreach比for快的原因之一)
Bucket *pListHead; // 存儲數組頭元素指針
Bucket *pListTail; // 存儲數組尾元素指針
Bucket **arBuckets; // 存儲hash數組
dtor_func_t pDestructor; // 在刪除元素時執行的回調函數,用於資源的釋放
zend_bool persistent; //指出了Bucket內存分配的方式。如果persisient為TRUE,則使用操作系統本身的內存分配函數為Bucket分配內存,否則使用PHP的內存分配函數。
unsigned char nApplyCount; // 標記當前hash Bucket被遞歸訪問的次數(防止多次遞歸)
zend_bool bApplyProtection;// 標記當前hash桶允許不允許多次訪問,不允許時,最多只能遞歸3次
#if ZEND_DEBUG
int inconsistent;
#endif
} HashTable;
count直接獲取nNumOfElements大小,所以也是O(1)
補充————————————————
count() 函數的定義在這裡
/* {{{ proto int count(mixed var [, int mode])
Count the number of elements in a variable (usually an array) */
PHP_FUNCTION(count)
{
zval *array;
zend_long mode = COUNT_NORMAL;
zend_long cnt;
zval *element;
ZEND_PARSE_PARAMETERS_START(1, 2)
Z_PARAM_ZVAL(array)
Z_PARAM_OPTIONAL
Z_PARAM_LONG(mode)
ZEND_PARSE_PARAMETERS_END();
switch (Z_TYPE_P(array)) {
case IS_NULL:
php_error_docref(NULL, E_WARNING, “Parameter must be an array or an object that implements Countable”);
RETURN_LONG(0);
break;
case IS_ARRAY:
if (mode != COUNT_RECURSIVE) {
//類型為數組時調用zend內核函數 zend_array_count()
cnt = zend_array_count(Z_ARRVAL_P(array));
} else {
cnt = php_count_recursive(Z_ARRVAL_P(array));
}
RETURN_LONG(cnt);
break;
case IS_OBJECT: {
zval retval;
/* first, we check if the handler is defined */
if (Z_OBJ_HT_P(array)-count_elements) {
RETVAL_LONG(1);
if (SUCCESS == Z_OBJ_HT(*array)-count_elements(array, Z_LVAL_P(return_value))) {
return;
}
}
/* if not and the object implements Countable we call its count() method */
if (instanceof_function(Z_OBJCE_P(array), zend_ce_countable)) {
zend_call_method_with_0_params(array, NULL, NULL, “count”, retval);
if (Z_TYPE(retval) != IS_UNDEF) {
RETVAL_LONG(zval_get_long(retval));
zval_ptr_dtor(retval);
}
return;
}
/* If There’s no handler and it doesn’t implement Countable then add a warning */
php_error_docref(NULL, E_WARNING, “Parameter must be an array or an object that implements Countable”);
RETURN_LONG(1);
break;
}
default:
php_error_docref(NULL, E_WARNING, “Parameter must be an array or an object that implements Countable”);
RETURN_LONG(1);
break;
}
}
如果沒有特別指定mode參數為 COUNT_RECURSIVE 的話(即作遍歷),跳轉到 zend 的數組計數函數 zend_array_count()
#define zend_hash_num_elements(ht) \
(ht)-nNumOfElements
…
…
static uint32_t zend_array_recalc_elements(HashTable *ht)
{
zval *val;
uint32_t num = ht-nNumOfElements;
ZEND_HASH_FOREACH_VAL(ht, val) {
if (Z_TYPE_P(val) == IS_INDIRECT) {
if (UNEXPECTED(Z_TYPE_P(Z_INDIRECT_P(val)) == IS_UNDEF)) {
num–;
}
}
} ZEND_HASH_FOREACH_END();
return num;
}
ZEND_API uint32_t zend_array_count(HashTable *ht)
{
uint32_t num;
if (UNEXPECTED(ht-u.v.flags HASH_FLAG_HAS_EMPTY_IND)) {
num = zend_array_recalc_elements(ht);
if (UNEXPECTED(ht-nNumOfElements == num)) {
ht-u.v.flags = ~HASH_FLAG_HAS_EMPTY_IND;
}
} else if (UNEXPECTED(ht == EG(symbol_table))) {
num = zend_array_recalc_elements(ht);
} else {
num = zend_hash_num_elements(ht);
}
return num;
}
IS_REFERENCE:間接 zval 指的就是其真正的值是存儲在其他地方的。注意這個 IS_REFERENCE 類型是不同的,間接 zval 是直接指向另外一個 zval 而不是像 zend_reference 結構體一樣嵌入 zval。
只有當數組中有 HASH_FLAG_HAS_EMPTY_IND 這個 flag 時(間接zval)才會對數組進行遍歷校驗,其他情況下都是直接取 數組(hash table) 裏面的 nNumOfElements 的值,答案顯而易見了,就是O(1)
PHP出現 unexpected T_STRING 錯誤,這裡的T_STRING什麼意思?
是字符串常量的意思,意思就是:在php中,單獨的字符串會被認為是常量,但是,當它去找該常量的值的時候沒有找到,就會告訴你,未定義的字符串常量!
php語句,retval是什麼意思
array() 創建數組,帶有鍵和值。如果在規定數組時省略了鍵,則生成一個整數鍵,這個 key 從 0 開始,然後以 1 進行遞增。 要用 array() 創建一個關聯數組
PHP執行linux系統命令的常用函數使用說明
system函數
說明:執行外部程序並顯示輸出資料。
語法:string
system(string
command,
int
[return_var]);
返回值:
字符串
詳細介紹:
本函數就像是
C
語中的函數
system(),用來執行指令,並輸出結果。若是
return_var
參數存在,則執行
command
之後的狀態會填入
return_var
中。同樣值得注意的是若需要處理用戶輸入的資料,而又要防止用戶耍花招破解系統,則可以使用
EscapeShellCmd()。若
PHP
以模塊式的執行,本函數會在每一行輸出後自動更新
Web
服務器的輸出緩衝暫存區。若需要完整的返回字符串,且不想經過不必要的其它中間的輸出界面,可以使用
PassThru()。
實例代碼:
複製代碼
代碼如下:
?php
$last_line
=
system(‘ls’,
$retval);
echo
‘Last
line
of
the
output:
‘
.
$last_line;
echo
‘hr
/Return
value:
‘
.
$retval;
?
exec函數
說明:執行外部程序。
語法:string
exec(string
command,
string
[array],
int
[return_var]);
返回值:
字符串
詳細介紹:
本函數執行輸入
command
的外部程序或外部指令。它的返回字符串只是外部程序執行後返回的最後一行;若需要完整的返回字符串,可以使用
PassThru()
這個函數。
要是參數
array
存在,command
會將
array
加到參數中執行,若不欲
array
被處理,可以在執行
exec()
之前呼叫
unset()。若是
return_var
跟
array
二個參數都存在,則執行
command
之後的狀態會填入
return_var
中。
值得注意的是若需要處理使用者輸入的資料,而又要防止使用者耍花招破解系統,則可以使用
EscapeShellCmd()。
實例代碼:
複製代碼
代碼如下:
?php
echo
exec(‘whoami’);
?
popen函數
說明:打開文件。
語法:int
popen(string
command,
string
mode);
返回值:
整數
詳細介紹:
本函數執行指令開檔,而該文件是用管道方式處理的文件。用本函數打開的文件只能是單向的
(只能讀或只能寫),而且一定要用
pclose()
關閉。在文件操作上可使用
fgets()、fgetss()
與
fputs()。若是開檔發生錯誤,返回
false
值。
實例代碼:
複製代碼
代碼如下:
?
$fp
=
popen(“/bin/ls”,”r”
);
?
PHP監控linux服務器負載
在實際項目的應用中,我們由於各種條件的現實,利用PHP來實現服務器負載監控將是一種更為靈活的方式。
由於Web
Server以及PHP的實現方式所限,我們在現實環境中很難利用PHP去調用一些Linux中需要root權限才能執行的程序,對此,我從網上找到另外一種方式來繞開這個限制。首先先寫個c程序中轉調用系統命令,然後用PHP去執行此c程序。
c程序
首先寫個c文件,比如/usr/local/ismole/w.c
複製代碼
代碼如下:
#includestdio.h
#includestdlib.h
#includesystypes.h
#includeunistd.h
int
main()
{
uid_t
uid
,euid;
//note
獲得當前的uid
uid
=
getuid();
//note
獲得當前euid
euid
=
geteuid();
//note
交換這兩個id
if(setreuid(euid,
uid))
perror(“setreuid”);
//note
執行將要執行linux系統命令
system(“/usr/bin/w”);
return0;
}
編譯該文件gcc
-o
w
-Wall
w.c,這時會在當前目錄下生成程序w。改變此程序的屬主chmod
u+s
./w。
PHP執行
文件內容如下,放在web目錄下,訪問就會輸出當前的服務器負載情況。
複製代碼
代碼如下:
?php
/*
More
Original
PHP
Framwork
Copyright
(c)
2007
–
2008
IsMole
Inc.
$Id:
serverMonitor.php
408
2008-12-02
08:07:40Z
kimi
$
*/
//note
key的驗證過程
if($key
!=
$authkey)
{
//
exit(‘key
error);
}
$last_line
=
exec(‘/usr/local/ismole/w’,
$retval);
$returnArray
=
explode(“load
average:
“,
$retval[0]);
$returnString
=
$returnArray[1];
echo
$returnString;
按照上面的實例,我們可以用PHP來做任何我們想執行的Linux系統命令,SVN更新,服務器監控,備份,恢復,日常維護等等。
php的 strval和string有啥區別?
1.表面看着沒有區別
2.但是在精度計算上就體現出來了
3.比如 $num = 5.2*100;
4.如果單純存儲數據沒有區別 如果你進行數據庫運算查詢的時候兩個就完全有區別了
5.比如你數據庫字段上有一個字段類型為int num 值為 520
6.這時你會發現用(string)$num查詢是查詢不到信息 但是用 strval($num)這時絕對可以查詢出來
PHP怎麼從COM組件中獲取返回的字符串
PHP如何從COM組件中獲取返回的字符串?
COM組件中定義一個方法
HRESULT GetStr([in,out] BSTR* vStr, [in,out] LONG* vLen, [out,retval] LONG* vError);
方法實現為:
C/C++ code
STDMETHODIMP MC_MyClass::GetStr(BSTR* vStr, LONG* vLen, LONG* vError) { *vError = 0; if(0 == vStr) return S_FALSE; if(0 == vLen) return S_FALSE; wchar_t tStr[] = L”This is a string from com!”; memcpy(*vStr, tStr, wcslen(tStr)); *vLen = wcslen(tStr); *vError = 1; return S_OK; }
PHP調用該方法
C/C++ code
$tStr = “”; $tLen = 100; $tStr = str_pad($tStr, $tLen, “0”); $tRes = $tCom-GetStr($tStr, $tLen);
結果
$tRes = 1;
$tStr = “”;
$tLen = 26;
原創文章,作者:XYTW,如若轉載,請註明出處:https://www.506064.com/zh-hk/n/137192.html