包含phpretvalstring的詞條

本文目錄一覽:

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

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
XYTW的頭像XYTW
上一篇 2024-10-04 00:17
下一篇 2024-10-04 00:17

相關推薦

發表回復

登錄後才能評論