php7變量實(shí)現(xiàn)_zval

php5的變量實(shí)現(xiàn)

php通過(guò)一個(gè)zval結(jié)構(gòu)體來(lái)實(shí)現(xiàn)變量,對(duì)于全局變量,php維護(hù)一個(gè)全局的hashtable,通過(guò)某種散列關(guān)系將變量名和對(duì)應(yīng)的zval指針保存起來(lái)瞒御,這個(gè)hashtable稱(chēng)為symbol_table。對(duì)于函數(shù)神郊,會(huì)建立一個(gè)局部的hashtable存儲(chǔ)局部變量肴裙。php中的非對(duì)象/資源變量在傳參時(shí)傳遞的是值,但實(shí)際上也是傳遞的指針涌乳,將局部hashtable中相應(yīng)的變量映射到全局hashtable中的相應(yīng)指針中蜻懦,這是為了減少內(nèi)存和時(shí)間開(kāi)銷(xiāo)采用了寫(xiě)時(shí)拷貝機(jī)制。

寫(xiě)時(shí)拷貝(copy on write):在需要復(fù)制一個(gè)資源時(shí)夕晓,并不總是直接復(fù)制值宛乃,而是首先選擇復(fù)制指針,當(dāng)兩個(gè)指向同一資源的兩個(gè)變量中的一個(gè)需要發(fā)生改變時(shí)再進(jìn)行值復(fù)制蒸辆。在很多時(shí)候征炼,資源并不會(huì)被改變,采用COW機(jī)制可以減少很多不必要的時(shí)間和空間開(kāi)銷(xiāo)吁朦。Linux中的fork函數(shù)就采用的這種機(jī)制柒室。

與之對(duì)應(yīng)的機(jī)制稱(chēng)為寫(xiě)時(shí)改變(change on write):當(dāng)值發(fā)生改變時(shí)渡贾,直接改變值如$b=&$a逗宜。

那么php如何分辨一個(gè)zval是copy on write/change on write。如果一個(gè)zval是copy on write的空骚,如a=b纺讲,那么這個(gè)zval的refcount=2。refcount>2表示當(dāng)前zval被多于1個(gè)的變量引用囤屹,那么某一個(gè)變量對(duì)改zval值進(jìn)行修改時(shí)熬甚,需要首先將該zval拷貝一份,并將拷貝的副本分配給需要修改的變量再進(jìn)行修改肋坚,這個(gè)過(guò)程稱(chēng)為分離乡括。如果一個(gè)zval是change on write的肃廓,如$a=&$b,那么php會(huì)將該zval的is_ref__gc置1標(biāo)志該zval成為一個(gè)引用诲泌,對(duì)該zval指進(jìn)行修改時(shí)不會(huì)進(jìn)行分離盲赊。那么一個(gè)變量即存在cpoy又存在change怎么處理呢,如果對(duì)一個(gè)copy的zval進(jìn)行change on write處理時(shí)敷扫,判斷到refcount>1哀蘑,那么會(huì)首先對(duì)該zval進(jìn)行分離再進(jìn)行change on write處理。如果對(duì)一個(gè)change的zval進(jìn)行copy on write處理葵第,那么直接拷貝當(dāng)前zval绘迁。可以看下面的代碼

//php5.6
<?php
    $a = '1';
    $b = $a;//copy on write
    debug_zval_dump($a);//輸出string(1) "1" refcount(3)卒密,有三個(gè)變量指向當(dāng)前zval缀台,因?yàn)閷?xiě)時(shí)拷貝機(jī)制,$a哮奇,$b和傳進(jìn)debug_zval_dump()的參數(shù)都是指向了當(dāng)前zval
    $c = $a;
    debug_zval_dump($a);//輸出string(1) "1" refcount(4)
    $d = &$a;
    debug_zval_dump($a);//輸出string(1) "1" refcount(1)将硝,對(duì)一個(gè)copy變量$a進(jìn)行change on write處理,首先進(jìn)行分離屏镊。那么$a和$d已經(jīng)是一對(duì)change on write的變量了依疼,此時(shí)再傳入debug_zval_dump()函數(shù),函數(shù)傳參時(shí)也是值傳遞即copy on write而芥,對(duì)一個(gè)change的zval進(jìn)行copy on write處理律罢,會(huì)直接拷貝zval,因此傳入的參數(shù)是一個(gè)獨(dú)立的變量所有refcount=1棍丐。

php5中的zval結(jié)構(gòu)體_zval_struct實(shí)現(xiàn)

struct _zval_struct {
    union {
        long lval;
        double dval;
        struct {
            char *val;//字節(jié)型指針8字節(jié)
            int len;//整型4字節(jié)
        } str;
        HashTable *ht;
        zend_object_value obj;
        zend_ast *ast;
    } value;//value變量通過(guò)一個(gè)聯(lián)合體儲(chǔ)存變量的值或指針
    zend_uint refcount__gc;//計(jì)數(shù)误辑,指向當(dāng)前值的變量數(shù),在debug_zval_dump()函數(shù)中輸出的refcount
    zend_uchar type;//變量類(lèi)型標(biāo)志位
    zend_uchar is_ref__gc;//引用標(biāo)志位歌逢,用于標(biāo)志當(dāng)前值是否是引用如$b=&$a
};

在這個(gè)_zval_struct結(jié)構(gòu)體中巾钉,最主要的部分是一個(gè)value聯(lián)合體,這個(gè)聯(lián)合體儲(chǔ)存了變量的值或指針秘案,變量的類(lèi)型由zend_uchar類(lèi)型的type確定砰苍。在value聯(lián)合體中最大的部分是str結(jié)構(gòu)體占用12字節(jié)內(nèi)存,在內(nèi)存對(duì)齊的情況下阱高,value共占用16字節(jié)內(nèi)存赚导。剩下的部分包括一個(gè)4個(gè)字節(jié)的zend_uint類(lèi)型的refcount__gc和兩個(gè)單字節(jié)zend_uchar類(lèi)型的type和is_ref__gc,在內(nèi)存對(duì)齊的情況下zval結(jié)構(gòu)體共占用24字節(jié)內(nèi)存赤惊,并且沒(méi)有預(yù)留下拓展的空間吼旧。在5.3以后的版本中,為了解決數(shù)組和字符串變量的循環(huán)引用問(wèn)題未舟,使用了一個(gè)新的zval_gc_info結(jié)構(gòu)體來(lái)擴(kuò)充zval圈暗,這個(gè)結(jié)構(gòu)體占8字節(jié)掂为。這樣在php5中,一個(gè)變量會(huì)至少占用32字節(jié)內(nèi)存员串。并且由于zval結(jié)構(gòu)和cow機(jī)制造成很大的空間和時(shí)間開(kāi)銷(xiāo)菩掏,如以下代碼:

//php5.6
$a = '1';
$b = &$a;
print_r($a);

這里傳入print_r()函數(shù)的參數(shù)本可以利用cow機(jī)制避免不必要的開(kāi)銷(xiāo),但是由于$a在第二行和$b進(jìn)行了change on write綁定昵济,使$a成為了一個(gè)引用智绸,那么在函數(shù)傳遞參數(shù)時(shí),由于字符串是通過(guò)值傳遞即copy on write的访忿,那么對(duì)一個(gè)change的zval進(jìn)行copy on write時(shí)必須要進(jìn)行分離瞧栗,即使函數(shù)內(nèi)并沒(méi)有對(duì)該變量進(jìn)行修改。如果這個(gè)函數(shù)在一個(gè)循環(huán)里重復(fù)運(yùn)行幾千幾萬(wàn)次海铆,就會(huì)造成很大的無(wú)效開(kāi)銷(xiāo)迹恐。

php7中的變量實(shí)現(xiàn)

struct _zval_struct {
     union {
          zend_long         lval;            //long value
          double            dval;            //double value
          zend_refcounted  *counted;
          zend_string      *str;
          zend_array       *arr;
          zend_object      *obj;
          zend_resource    *res;
          zend_reference   *ref;            //refenerce 
          zend_ast_ref     *ast;            //abstract syntax tree
          zval             *zv;
          void             *ptr;
          zend_class_entry *ce;
          zend_function    *func;
          struct {
               uint32_t w1;
               uint32_t w2;
          } ww;
     } value;
    union {
        struct {
            ZEND_ENDIAN_LOHI_4(
                zend_uchar    type,         //類(lèi)型標(biāo)志如字符串,整型等
                zend_uchar    type_flags,   //變量類(lèi)型標(biāo)志位如需要引用計(jì)數(shù)卧斟,可被復(fù)制等
                zend_uchar    const_flags,  //常量標(biāo)志位
                zend_uchar    reserved     //保留字段
        } v;
        uint32_t type_info;//u1是一個(gè)聯(lián)合體殴边,所以實(shí)際上type_info的值就是上面ZEND_ENDIAN_LOHI_4結(jié)構(gòu)體的值,通過(guò)type_info可以簡(jiǎn)化賦值珍语。
    } u1;
    union {
        uint32_t     var_flags;
        uint32_t     next;                 /* hash collision chain */
        uint32_t     cache_slot;           /* literal cache slot */
        uint32_t     lineno;               /* line number (for ast nodes) */
        uint32_t     num_args;             /* arguments number for EX(This) */
        uint32_t     fe_pos;               /* foreach position */
        uint32_t     fe_iter_idx;          /* foreach iterator index */
    } u2;
};

php7的zval通過(guò)一個(gè)value聯(lián)合體保存變量锤岸,一個(gè)u1聯(lián)合體記錄變量類(lèi)型,u2聯(lián)合體為各種輔助變量板乙。value8字節(jié)是偷,u1和u2分別為4字節(jié),共16字節(jié)募逞,相比php5節(jié)省了一半的內(nèi)存蛋铆。

value中可以保存一個(gè)指針或者一個(gè)long/double。在php7中引用獨(dú)立出來(lái)成為一種類(lèi)型的變量放接。u1中的type類(lèi)型定義如下

/* regular data types */
#define IS_UNDEF                    0       //標(biāo)記為未定義刺啦,如unset后的變量
#define IS_NULL                     1
#define IS_FALSE                    2       //對(duì)于布爾類(lèi)型,直接在type中儲(chǔ)存了指IS_FALSE/IS_TRUE
#define IS_TRUE                     3
#define IS_LONG                     4
#define IS_DOUBLE                   5
#define IS_STRING                   6
#define IS_ARRAY                    7
#define IS_OBJECT                   8
#define IS_RESOURCE                 9
#define IS_REFERENCE               10
/* constant expressions */
#define IS_CONSTANT                 11
#define IS_CONSTANT_AST             12
/* fake types */
#define _IS_BOOL                    13
#define IS_CALLABLE                 14
#define IS_ITERABLE                19
#define IS_VOID                    18
/* internal types */
#define IS_INDIRECT                 15
#define IS_PTR                      17
#define IS_ERROR                  20

通過(guò)type值取出相應(yīng)的value值纠脾。如果是IS_LONG/IS_DOUBLE則直接取出value值作為zval值玛瘸,若是IS_FLASE/IS_TRUE則直接把type作為zval值,否則獲取相應(yīng)指針獲取值乳乌。php7中的long和double不再使用COW機(jī)制捧韵。

u1中的type_flags用于標(biāo)記變量的一些屬性市咆,8位的type_flags中每一位都可以表示一個(gè)標(biāo)志汉操,最多可以同時(shí)有8個(gè)標(biāo)志如下

//zval,作用于zval也就是zval.u1.v.type_flags
IS_TYPE_CONSTANT            //是常量類(lèi)型
IS_TYPE_IMMUTABLE           //不可變的類(lèi)型蒙兰, 比如存在共享內(nèi)存的數(shù)組
IS_TYPE_REFCOUNTED          //需要引用計(jì)數(shù)的類(lèi)型
IS_TYPE_COLLECTABLE         //可能包含循環(huán)引用的類(lèi)型(IS_ARRAY, IS_OBJECT)
IS_TYPE_COPYABLE            //可被復(fù)制的類(lèi)型磷瘤, 如對(duì)象和資源就不是
IS_TYPE_SYMBOLTABLE         //zval保存的是全局符號(hào)表
//以下作用與具體變量的gc.u.v.flags
//string
IS_STR_PERSISTENT             //是malloc分配內(nèi)存的字符串
IS_STR_INTERNED             //INTERNED STRING
IS_STR_PERMANENT            //不可變的字符串芒篷, 用作哨兵作用
IS_STR_CONSTANT             //代表常量的字符串
IS_STR_CONSTANT_UNQUALIFIED //帶有可能命名空間的常量字符串
//array
IS_ARRAY_IMMUTABLE  //同IS_TYPE_IMMUTABLE
//object
IS_OBJ_APPLY_COUNT          //遞歸保護(hù)
IS_OBJ_DESTRUCTOR_CALLED    //析構(gòu)函數(shù)已經(jīng)調(diào)用
IS_OBJ_FREE_CALLED          //清理函數(shù)已經(jīng)調(diào)用
IS_OBJ_USE_GUARDS           //魔術(shù)方法遞歸保護(hù)
IS_OBJ_HAS_GUARDS           //是否有魔術(shù)方法遞歸保護(hù)標(biāo)志

zend_refcounted_h,在需要進(jìn)行引用計(jì)數(shù)的數(shù)據(jù)類(lèi)型結(jié)構(gòu)體中都包含這個(gè)結(jié)構(gòu)體采缚,gc通過(guò)這個(gè)結(jié)構(gòu)體來(lái)實(shí)現(xiàn)垃圾回收针炉,gc可以不關(guān)心數(shù)據(jù)的類(lèi)型。

typedef struct _zend_refcounted_h {
    uint32_t         refcount;          /* reference counter 32-bit */
    union {
        struct {
            ZEND_ENDIAN_LOHI_3(
                zend_uchar    type,
                zend_uchar    flags,    /* used for strings & objects */
                uint16_t      gc_info)  /* keeps GC root number (or 0) and color */
        } v;
        uint32_t type_info;
    } u;
} zend_refcounted_h;

字符串

struct _zend_string{
    zend_refcounted_h   gc;     //一個(gè)gc結(jié)構(gòu)體和媳,儲(chǔ)存了gc相關(guān)的信息漠其,使gc進(jìn)行垃圾回收時(shí)可以不關(guān)心數(shù)據(jù)類(lèi)型
    zend_ulong          h;      //字符串哈希值留美,避免數(shù)組訪問(wèn)時(shí)重復(fù)計(jì)算哈希值,當(dāng)字符串被當(dāng)作數(shù)組索引時(shí)才計(jì)算該值
    sizt_t              len;
    char                val[1]; //柔性數(shù)組
}

對(duì)于一個(gè)字符串結(jié)構(gòu)體镰烧,我們可以直接用一個(gè)char指針來(lái)儲(chǔ)存字符串,但是這樣在訪問(wèn)字符串時(shí)需要兩次訪問(wèn)內(nèi)存楞陷,一次是讀地址怔鳖,一次是讀數(shù)據(jù)。并且在釋放資源時(shí)也要先釋放字符串指針再釋放結(jié)構(gòu)體固蛾。在C99標(biāo)準(zhǔn)中加入了一種柔性數(shù)組的結(jié)構(gòu)结执,可以使php中的字符串操作更高效

那么如何改進(jìn)呢?很容易想到艾凯,我們將字符串值和結(jié)構(gòu)體存儲(chǔ)在一片連續(xù)的內(nèi)存空間就可以了献幔。這樣的話(huà),訪問(wèn)字符串與釋放字符串的內(nèi)存空間趾诗,均僅需1次內(nèi)存訪問(wèn)斜姥。

鑒于這種代碼結(jié)構(gòu)所產(chǎn)生的重要作用,C99甚至把它收入了標(biāo)準(zhǔn)中沧竟。C99使用不完整類(lèi)型實(shí)現(xiàn)柔性數(shù)組成員铸敏,在C99 中,結(jié)構(gòu)中的最后一個(gè)元素允許是未知大小的數(shù)組悟泵,這就叫做柔性數(shù)組(flexible array)成員(也叫伸縮性數(shù)組成員)杈笔,但結(jié)構(gòu)中的柔性數(shù)組成員前面必須至少一個(gè)其他成員。柔性數(shù)組成員允許結(jié)構(gòu)中包含一個(gè)大小可變的數(shù)組糕非。柔性數(shù)組成員只作為一個(gè)符號(hào)地址存在蒙具,而且必須是結(jié)構(gòu)體的最后一個(gè)成員,sizeof 返回的這種結(jié)構(gòu)大小不包括柔性數(shù)組的內(nèi)存朽肥。柔性數(shù)組成員不僅可以用于字符數(shù)組禁筏,還可以是元素為其它類(lèi)型的數(shù)組。包含柔性數(shù)組成員的結(jié)構(gòu)用malloc ()函數(shù)進(jìn)行內(nèi)存的動(dòng)態(tài)分配衡招,并且分配的內(nèi)存應(yīng)該大于結(jié)構(gòu)的大小篱昔,以適應(yīng)柔性數(shù)組的預(yù)期大小

  • 第一個(gè)問(wèn)題:為什么要存長(zhǎng)度len?不存長(zhǎng)度州刽,直接和C語(yǔ)言一樣通過(guò)字符串的'\0'來(lái)判斷字符串結(jié)束不行嗎空执?不行。這里有一個(gè)二進(jìn)制安全的問(wèn)題穗椅。
    • 二進(jìn)制安全:寫(xiě)入的數(shù)據(jù)和讀出來(lái)的數(shù)據(jù)完全相同辨绊,就是二進(jìn)制安全的。
    • 假設(shè)你寫(xiě)入了一個(gè)字符串的內(nèi)容為:hello\0world匹表,按照C語(yǔ)言的讀取字符串的方法就會(huì)判定\0是字符串結(jié)束的標(biāo)志门坷,讀出來(lái)就是hello,這樣讀出來(lái)的數(shù)據(jù)就和寫(xiě)入的數(shù)據(jù)不一致袍镀,就是非二進(jìn)制安全的拜鹤。
    • 如果存了長(zhǎng)度,就不會(huì)管你是否有\(zhòng)0流椒,從頭開(kāi)始讀字符串敏簿,一直讀len長(zhǎng)度為止即可。
  • 第二個(gè)問(wèn)題:最后一個(gè)字段改成char val[0]可以嗎宣虾?可以惯裕。寫(xiě)成char val[1]是出于可移植性的考慮。有些編譯器不支持[0]數(shù)組绣硝,可將其改成[]或[1]均可蜻势。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(char * args[]){
    typedef struct s {
        int a;
        char b[0];
    }s;
    s * a = (s*)(malloc(sizeof(s)+4*sizeof(char)));
    a->a = 4;
    strcpy(a->b, "he");

}
(gdb) b main
Breakpoint 1 at 0x1149: file string.c, line 5.
(gdb) run
Starting program: /home/whye/Desktop/php/phpsrc/str 

Breakpoint 1, main (args=0x555555555060 <_start>) at string.c:5
5   int main(char * args[]){
(gdb) 
(gdb) n
10      s * a = (s*)(malloc(sizeof(s)+4*sizeof(char)));
(gdb) 
11      a->a = 4;
(gdb) 
12      strcpy(a->b, "he");
(gdb) 
14  }
(gdb) p a
$1 = (s *) 0x5555555592a0
(gdb) p *a
$2 = {a = 4, b = 0x5555555592a4 "he"}
(gdb) p sizeof(s)
$3 = 4
(gdb) p sizeof(a)
$4 = 8
(gdb) p a+1
$5 = (s *) 0x5555555592a4
(gdb) p (char*)(a+1)
$6 = 0x5555555592a4 "he"

引用實(shí)現(xiàn)

 struct _zend_reference {
     zend_refcounted_h gc;
     zval val;
 }

在php7中,引用也成為了一種數(shù)據(jù)類(lèi)型鹉胖,對(duì)于以下代碼

<?php
    $a = 'hello';
    $b = $a;
    $c = &$a;
php7_reference.png

上面的_zend_reference和_zend_string實(shí)例中g(shù)c計(jì)數(shù)均為2握玛。

參考

深入理解PHP原理之變量(Variables inside PHP)

深入理解PHP原理之變量作用域(Scope in PHP)

深入理解PHP原理之變量分離/引用(Variables Separation)

深入理解PHP7內(nèi)核之zval

PHP7源碼學(xué)習(xí) 2019-03-13 PHP字符串筆記

PHP內(nèi)核pemalloc的persistent硬編碼為1,我們?cè)撊绾稳ミM(jìn)行釋放

PHP內(nèi)核分析之深入理解字符串(七)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末甫菠,一起剝皮案震驚了整個(gè)濱河市挠铲,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌寂诱,老刑警劉巖拂苹,帶你破解...
    沈念sama閱讀 207,248評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異痰洒,居然都是意外死亡瓢棒,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門(mén)丘喻,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)脯宿,“玉大人,你說(shuō)我怎么就攤上這事泉粉×梗” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 153,443評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)窘面。 經(jīng)常有香客問(wèn)我翠语,道長(zhǎng)叽躯,這世上最難降的妖魔是什么财边? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,475評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮点骑,結(jié)果婚禮上酣难,老公的妹妹穿的比我還像新娘。我一直安慰自己黑滴,他們只是感情好憨募,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,458評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著袁辈,像睡著了一般菜谣。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上晚缩,一...
    開(kāi)封第一講書(shū)人閱讀 49,185評(píng)論 1 284
  • 那天尾膊,我揣著相機(jī)與錄音,去河邊找鬼荞彼。 笑死冈敛,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的鸣皂。 我是一名探鬼主播抓谴,決...
    沈念sama閱讀 38,451評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼寞缝!你這毒婦竟也來(lái)了癌压?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,112評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤荆陆,失蹤者是張志新(化名)和其女友劉穎措拇,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體慎宾,經(jīng)...
    沈念sama閱讀 43,609評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡丐吓,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,083評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了趟据。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片券犁。...
    茶點(diǎn)故事閱讀 38,163評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖汹碱,靈堂內(nèi)的尸體忽然破棺而出粘衬,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 33,803評(píng)論 4 323
  • 正文 年R本政府宣布稚新,位于F島的核電站勘伺,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏褂删。R本人自食惡果不足惜飞醉,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,357評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望屯阀。 院中可真熱鬧缅帘,春花似錦、人聲如沸难衰。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,357評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)盖袭。三九已至失暂,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間鳄虱,已是汗流浹背弟塞。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,590評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留醇蝴,地道東北人宣肚。 一個(gè)月前我還...
    沈念sama閱讀 45,636評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像悠栓,于是被迫代替她去往敵國(guó)和親霉涨。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,925評(píng)論 2 344