├── .gitbook └── assets │ ├── image (1).png │ ├── image (10).png │ ├── image (100).png │ ├── image (101).png │ ├── image (102).png │ ├── image (103).png │ ├── image (104).png │ ├── image (105).png │ ├── image (106).png │ ├── image (107).png │ ├── image (108).png │ ├── image (109).png │ ├── image (11).png │ ├── image (110).png │ ├── image (111).png │ ├── image (112).png │ ├── image (113).png │ ├── image (114).png │ ├── image (115).png │ ├── image (116).png │ ├── image (117).png │ ├── image (118).png │ ├── image (119).png │ ├── image (12).png │ ├── image (120).png │ ├── image (121).png │ ├── image (122).png │ ├── image (123).png │ ├── image (124).png │ ├── image (125).png │ ├── image (126).png │ ├── image (127).png │ ├── image (128).png │ ├── image (129).png │ ├── image (13).png │ ├── image (130).png │ ├── image (131).png │ ├── image (132).png │ ├── image (133).png │ ├── image (134).png │ ├── image (135).png │ ├── image (136).png │ ├── image (137).png │ ├── image (138).png │ ├── image (139).png │ ├── image (14).png │ ├── image (140).png │ ├── image (141).png │ ├── image (142).png │ ├── image (143).png │ ├── image (144).png │ ├── image (145).png │ ├── image (146).png │ ├── image (147).png │ ├── image (148).png │ ├── image (149).png │ ├── image (15).png │ ├── image (150).png │ ├── image (151).png │ ├── image (152).png │ ├── image (153).png │ ├── image (154).png │ ├── image (155).png │ ├── image (156).png │ ├── image (157).png │ ├── image (158).png │ ├── image (159).png │ ├── image (16).png │ ├── image (160).png │ ├── image (161).png │ ├── image (162).png │ ├── image (163).png │ ├── image (164).png │ ├── image (165).png │ ├── image (166).png │ ├── image (167).png │ ├── image (168).png │ ├── image (169).png │ ├── image (17).png │ ├── image (170).png │ ├── image (171).png │ ├── image (172).png │ ├── image (173).png │ ├── image (174).png │ ├── image (175).png │ ├── image (176).png │ ├── image (177).png │ ├── image (178).png │ ├── image (179).png │ ├── image (18).png │ ├── image (180).png │ ├── image (181).png │ ├── image (182).png │ ├── image (183).png │ ├── image (184).png │ ├── image (185).png │ ├── image (186).png │ ├── image (187).png │ ├── image (188).png │ ├── image (189).png │ ├── image (19).png │ ├── image (190).png │ ├── image (191).png │ ├── image (192).png │ ├── image (193).png │ ├── image (194).png │ ├── image (195).png │ ├── image (196).png │ ├── image (197).png │ ├── image (198).png │ ├── image (199).png │ ├── image (2).png │ ├── image (20).png │ ├── image (200).png │ ├── image (201).png │ ├── image (202).png │ ├── image (203).png │ ├── image (204).png │ ├── image (205).png │ ├── image (206).png │ ├── image (207).png │ ├── image (208).png │ ├── image (209).png │ ├── image (21).png │ ├── image (210).png │ ├── image (211).png │ ├── image (212).png │ ├── image (213).png │ ├── image (214).png │ ├── image (215).png │ ├── image (216).png │ ├── image (217).png │ ├── image (218).png │ ├── image (219).png │ ├── image (22).png │ ├── image (220).png │ ├── image (221).png │ ├── image (222).png │ ├── image (223).png │ ├── image (224).png │ ├── image (225).png │ ├── image (226).png │ ├── image (227).png │ ├── image (228).png │ ├── image (229).png │ ├── image (23).png │ ├── image (230).png │ ├── image (231).png │ ├── image (232).png │ ├── image (233).png │ ├── image (234).png │ ├── image (235).png │ ├── image (236).png │ ├── image (237).png │ ├── image (238).png │ ├── image (239).png │ ├── image (24).png │ ├── image (240).png │ ├── image (241).png │ ├── image (242).png │ ├── image (243).png │ ├── image (244).png │ ├── image (25).png │ ├── image (26).png │ ├── image (27).png │ ├── image (28).png │ ├── image (29).png │ ├── image (3).png │ ├── image (30).png │ ├── image (31).png │ ├── image (32).png │ ├── image (33).png │ ├── image (34).png │ ├── image (35).png │ ├── image (36).png │ ├── image (37).png │ ├── image (38).png │ ├── image (39).png │ ├── image (4).png │ ├── image (40).png │ ├── image (41).png │ ├── image (42).png │ ├── image (43).png │ ├── image (44).png │ ├── image (45).png │ ├── image (46).png │ ├── image (47).png │ ├── image (48).png │ ├── image (49).png │ ├── image (5).png │ ├── image (50).png │ ├── image (51).png │ ├── image (52).png │ ├── image (53).png │ ├── image (54).png │ ├── image (55).png │ ├── image (56).png │ ├── image (57).png │ ├── image (58).png │ ├── image (59).png │ ├── image (6).png │ ├── image (60).png │ ├── image (61).png │ ├── image (62).png │ ├── image (63).png │ ├── image (64).png │ ├── image (65).png │ ├── image (66).png │ ├── image (67).png │ ├── image (68).png │ ├── image (69).png │ ├── image (7).png │ ├── image (70).png │ ├── image (71).png │ ├── image (72).png │ ├── image (73).png │ ├── image (74).png │ ├── image (75).png │ ├── image (76).png │ ├── image (77).png │ ├── image (78).png │ ├── image (79).png │ ├── image (8).png │ ├── image (80).png │ ├── image (81).png │ ├── image (82).png │ ├── image (83).png │ ├── image (84).png │ ├── image (85).png │ ├── image (86).png │ ├── image (87).png │ ├── image (88).png │ ├── image (89).png │ ├── image (9).png │ ├── image (90).png │ ├── image (91).png │ ├── image (92).png │ ├── image (93).png │ ├── image (94).png │ ├── image (95).png │ ├── image (96).png │ ├── image (97).png │ ├── image (98).png │ ├── image (99).png │ └── image.png ├── README.md ├── SUMMARY.md ├── mo-kuai-san.md ├── mo-kuai-san ├── README.md ├── gof-she-ji-mo-shi │ ├── README.md │ ├── gai-yao.md │ ├── hang-wei-xing.md │ └── jie-gou-xing.md ├── gou-jian-fa-huo-mo-kuai.md ├── gou-jian-he-xin-mo-kuai.md ├── gou-jian-ke-hu-mo-kuai.md ├── gou-jian-mu-lu-mo-kuai.md ├── gou-jian-xiao-shou-mo-kuai.md ├── gou-jian-zhi-fu-mo-kuai.md ├── mo-kuai-hua-wang-dian-ying-yong-de-xu-qiu-gui-fan │ ├── README.md │ ├── ding-yi-ji-shu-zhan.md │ ├── gai-yao.md │ └── xian-kuang-she-ji.md ├── solid-she-ji-yuan-ze │ ├── README.md │ ├── gai-yao.md │ ├── jie-kou-ge-li-yuan-ze.md │ ├── kai-bi-yuan-ze.md │ ├── li-shi-ti-huan-yuan-ze.md │ └── yi-lai-fan-zhuan-yuan-ze.md ├── symfony-gai-shu │ ├── README.md │ ├── biao-dan.md │ ├── bundle-xi-tong.md │ ├── ce-shi.md │ ├── chuang-jian-yi-ge-kong-bai-xiang-mu.md │ ├── kong-zhi-qi.md │ ├── lu-you.md │ ├── mo-ban.md │ ├── pei-zhi-symfony.md │ ├── shi-yong-symfony-kong-zhi-tai.md │ ├── shu-ju-ku-he-doctrine.md │ ├── xiao-jie.md │ └── yan-zheng.md └── zong-jie.md └── mo-kuai-yi ├── README.md ├── di-ba-zhang-chu-li-ri-qi-shi-jian-he-guo-ji-hua-fang-mian.md ├── di-ba-zhang-chu-li-ri-qi-shi-jian-he-guo-ji-hua-fang-mian ├── README.md ├── an-di-qu-chu-li-huo-bi.md ├── an-di-qu-she-zhi-ri-qi-shi-jian-ge-shi.md ├── an-di-qu-she-zhi-shu-zi-ge-shi.md ├── bu-shi-yong-gettext-chu-li-fan-yi.md ├── chuang-jian-yi-ge-html-guo-ji-ri-li-sheng-cheng-qi.md ├── cong-liu-lan-qi-shu-ju-huo-qu-yu-yan-huan-jing.md ├── gou-jian-yi-ge-zhou-qi-xing-shi-jian-sheng-cheng-qi.md ├── zai-shi-tu-jiao-ben-zhong-shi-yong-emoji.md └── zhuan-huan-fu-za-zi-fu.md ├── di-er-zhang-shi-yong-php-7-gao-xing-neng-te-xing.md ├── di-er-zhang-shi-yong-php-7-gao-xing-neng-te-xing ├── README.md ├── bian-li-hai-liang-wen-jian.md ├── di-gui-mu-lu-die-dai-qi.md ├── jiang-dian-zi-biao-ge-shang-chuan-dao-shu-ju-ku.md ├── le-jie-chou-xiang-yu-fa-shu.md ├── li-jie-foreach-chu-li-zhong-de-cha-yi.md ├── li-jie-ju-fa-fen-xi-zhong-de-cha-yi.md └── shi-yong-php-7-zeng-qiang-gong-neng-ti-gao-xing-neng.md ├── di-jiu-zhang-kai-fa-zhong-jian-jian.md ├── di-jiu-zhang-kai-fa-zhong-jian-jian ├── README.md ├── jin-hang-kuang-jia-jian-de-xi-tong-tiao-yong.md ├── shi-shi-lu-you-xuan-ze.md ├── shi-yong-gao-su-huan-cun-ti-gao-xing-neng.md ├── shi-yong-zhong-jian-jian-jin-xing-ren-zheng.md ├── shi-yong-zhong-jian-jian-lai-kua-yu-yan.md └── shi-yong-zhong-jian-jian-shi-xian-fang-wen-kong-zhi.md ├── di-liu-zhang-jian-li-ke-kuo-zhan-de-wang-zhan.md ├── di-liu-zhang-jian-li-ke-kuo-zhan-de-wang-zhan ├── README.md ├── chuang-jian-tong-yong-biao-dan-yuan-su-sheng-cheng-qi.md ├── chuang-jian-yi-ge-html-dan-xuan-yuan-su-sheng-cheng-qi.md ├── chuang-jian-yi-ge-html-xuan-ze-yuan-su-sheng-cheng-qi.md ├── jiang-yan-zheng-bang-ding-dao-biao-dan.md ├── lian-shi-post-guo-lv-qi.md ├── lian-shi-post-yan-zheng-qi.md └── shi-xian-biao-dan-gong-chang.md ├── di-qi-zhang-fang-wen-web-fu-wu.md ├── di-qi-zhang-fang-wen-web-fu-wu ├── README.md ├── chuang-jian-yi-ge-jian-dan-de-rest-fu-wu-qi.md ├── chuang-jian-yi-ge-jian-dan-de-rest-ke-hu-duan.md ├── chuang-jian-yi-ge-jian-dan-de-soap-fu-wu-qi.md ├── chuang-jian-yi-ge-jian-dan-de-soap-ke-hu-duan.md └── zai-php-he-xml-zhi-jian-zhuan-huan.md ├── di-san-zhang-shi-yong-php-han-shu.md ├── di-san-zhang-shi-yong-php-han-shu ├── README.md ├── han-shu-kai-fa.md ├── shi-yong-die-dai-qi.md ├── shi-yong-fan-hui-zhi-shu-ju-lei-xing.md ├── shi-yong-sheng-cheng-qi-bian-xie-zi-ji-de-die-dai-qi.md └── shu-ju-lei-xing-ti-shi.md ├── di-shi-er-zhang-ti-gao-wang-zhan-an-quan.md ├── di-shi-er-zhang-ti-gao-wang-zhan-an-quan ├── README.md ├── bao-hu-php-hui-hua.md ├── bu-shi-yong-mcrypt-jin-hang-jia-mi-jie-mi.md ├── dai-you-yan-zheng-ma-de-an-quan-bao-hu-biao-ge.md ├── guo-lv-post-shu-ju.md ├── jian-li-yi-ge-an-quan-de-mi-ma-sheng-cheng-qi.md ├── yan-zheng-post-shu-ju.md └── yong-ling-pai-bao-hu-biao-ge-de-an-quan.md ├── di-shi-san-zhang-zui-jia-shi-jian-ce-shi-he-tiao-shi.md ├── di-shi-san-zhang-zui-jia-shi-jian-ce-shi-he-tiao-shi ├── README.md ├── bian-xie-ce-shi-tao-jian.md ├── bian-xie-yi-ge-jian-dan-de-ce-shi.md ├── sheng-cheng-xu-jia-de-ce-shi-shu-ju.md ├── shi-yong-sessionstart-can-shu-zi-ding-yi-hui-hua.md ├── shi-yong-te-zheng-he-jie-kou.md ├── tong-yong-cuo-wu-chu-li-cheng-xu.md └── tong-yong-yi-chang-chu-li-cheng-xu.md ├── di-shi-yi-zhang-ruan-jian-she-ji-mo-shi-de-shi-xian.md ├── di-shi-yi-zhang-ruan-jian-she-ji-mo-shi-de-shi-xian ├── README.md ├── chuang-jian-shu-zu-dao-dui-xiang-de-zhuan-hua-qi.md ├── ding-yi-yi-ge-ying-she-qi.md ├── gou-jian-dui-xiang-dao-shu-zu-dao-zhuan-hua-qi.md ├── shi-shi-ce-lve-mo-shi.md ├── shi-shi-fa-bu-ding-yue-she-ji-mo-shi.md └── shi-xian-dui-xiang-guan-xi-ying-she.md ├── di-shi-zhang-gao-ji-suan-fa.md ├── di-shi-zhang-gao-ji-suan-fa ├── README.md ├── gou-jian-yi-ge-er-jin-zhi-sou-suo-lei.md ├── jian-li-mao-pao-pai-xu.md ├── shi-xian-yi-ge-dui-zhan.md ├── shi-xian-yi-ge-lian-biao.md ├── shi-xian-yi-ge-sou-suo-yin-qing.md ├── shi-yong-getter-he-setter.md └── xian-shi-duo-wei-shu-zu-bing-lei-ji-zong-shu.md ├── di-si-zhang-shi-yong-php-mian-xiang-dui-xiang-cheng-xu-she-ji.md ├── di-si-zhang-shi-yong-php-mian-xiang-dui-xiang-cheng-xu-she-ji ├── README.md ├── ding-yi-ke-jian-xing.md ├── lei-de-kai-fa.md ├── lei-de-kuo-zhan.md ├── shi-xian-ni-ming-lei.md ├── shi-yong-jie-kou.md ├── shi-yong-jing-tai-shu-xing-he-fang-fa.md ├── shi-yong-ming-ming-kong-jian.md └── shi-yong-te-xing.md ├── di-wu-zhang-yu-shu-ju-ku-de-jiao-hu.md ├── di-wu-zhang-yu-shu-ju-ku-de-jiao-hu ├── README.md ├── chu-li-fen-ye.md ├── ding-yi-shi-ti-yi-pi-pei-shu-ju-ku-biao.md ├── gou-jian-yi-ge-oop-sql-cha-xun-sheng-cheng-qi.md ├── jiang-er-ci-cha-zhao-qian-ru-dao-cha-xun-jie-guo-zhong.md ├── jiang-shi-ti-lei-yu-rdbms-cha-xun-bang-ding.md ├── shi-xian-jquery-datatables-de-php-cha-zhao.md └── shi-yong-pdo-lian-jie-shu-ju-ku.md └── di-yi-zhang-jian-li-ji-chu ├── README.md ├── an-zhuang-phpunit.md ├── chuang-jian-yi-ge-php-5-dao-php-7-dai-ma-zhuan-huan-qi.md ├── ding-yi-mysql-ce-shi-shu-ju-ku.md ├── jian-li-yi-ge-shen-du-wang-luo-sao-miao-qi.md ├── php-7-an-zhuang-zhu-yi-shi-xiang.md ├── shi-xian-lei-de-zi-dong-jia-zai.md ├── shi-yong-nei-zhi-de-php-web-fu-wu-qi.md └── zhua-qu-yi-ge-wang-zhan.md /.gitbook/assets/image (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (10).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (10).png -------------------------------------------------------------------------------- /.gitbook/assets/image (100).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (100).png -------------------------------------------------------------------------------- /.gitbook/assets/image (101).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (101).png -------------------------------------------------------------------------------- /.gitbook/assets/image (102).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (102).png -------------------------------------------------------------------------------- /.gitbook/assets/image (103).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (103).png -------------------------------------------------------------------------------- /.gitbook/assets/image (104).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (104).png -------------------------------------------------------------------------------- /.gitbook/assets/image (105).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (105).png -------------------------------------------------------------------------------- /.gitbook/assets/image (106).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (106).png -------------------------------------------------------------------------------- /.gitbook/assets/image (107).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (107).png -------------------------------------------------------------------------------- /.gitbook/assets/image (108).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (108).png -------------------------------------------------------------------------------- /.gitbook/assets/image (109).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (109).png -------------------------------------------------------------------------------- /.gitbook/assets/image (11).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (11).png -------------------------------------------------------------------------------- /.gitbook/assets/image (110).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (110).png -------------------------------------------------------------------------------- /.gitbook/assets/image (111).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (111).png -------------------------------------------------------------------------------- /.gitbook/assets/image (112).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (112).png -------------------------------------------------------------------------------- /.gitbook/assets/image (113).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (113).png -------------------------------------------------------------------------------- /.gitbook/assets/image (114).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (114).png -------------------------------------------------------------------------------- /.gitbook/assets/image (115).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (115).png -------------------------------------------------------------------------------- /.gitbook/assets/image (116).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (116).png -------------------------------------------------------------------------------- /.gitbook/assets/image (117).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (117).png -------------------------------------------------------------------------------- /.gitbook/assets/image (118).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (118).png -------------------------------------------------------------------------------- /.gitbook/assets/image (119).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (119).png -------------------------------------------------------------------------------- /.gitbook/assets/image (12).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (12).png -------------------------------------------------------------------------------- /.gitbook/assets/image (120).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (120).png -------------------------------------------------------------------------------- /.gitbook/assets/image (121).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (121).png -------------------------------------------------------------------------------- /.gitbook/assets/image (122).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (122).png -------------------------------------------------------------------------------- /.gitbook/assets/image (123).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (123).png -------------------------------------------------------------------------------- /.gitbook/assets/image (124).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (124).png -------------------------------------------------------------------------------- /.gitbook/assets/image (125).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (125).png -------------------------------------------------------------------------------- /.gitbook/assets/image (126).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (126).png -------------------------------------------------------------------------------- /.gitbook/assets/image (127).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (127).png -------------------------------------------------------------------------------- /.gitbook/assets/image (128).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (128).png -------------------------------------------------------------------------------- /.gitbook/assets/image (129).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (129).png -------------------------------------------------------------------------------- /.gitbook/assets/image (13).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (13).png -------------------------------------------------------------------------------- /.gitbook/assets/image (130).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (130).png -------------------------------------------------------------------------------- /.gitbook/assets/image (131).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (131).png -------------------------------------------------------------------------------- /.gitbook/assets/image (132).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (132).png -------------------------------------------------------------------------------- /.gitbook/assets/image (133).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (133).png -------------------------------------------------------------------------------- /.gitbook/assets/image (134).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (134).png -------------------------------------------------------------------------------- /.gitbook/assets/image (135).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (135).png -------------------------------------------------------------------------------- /.gitbook/assets/image (136).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (136).png -------------------------------------------------------------------------------- /.gitbook/assets/image (137).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (137).png -------------------------------------------------------------------------------- /.gitbook/assets/image (138).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (138).png -------------------------------------------------------------------------------- /.gitbook/assets/image (139).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (139).png -------------------------------------------------------------------------------- /.gitbook/assets/image (14).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (14).png -------------------------------------------------------------------------------- /.gitbook/assets/image (140).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (140).png -------------------------------------------------------------------------------- /.gitbook/assets/image (141).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (141).png -------------------------------------------------------------------------------- /.gitbook/assets/image (142).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (142).png -------------------------------------------------------------------------------- /.gitbook/assets/image (143).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (143).png -------------------------------------------------------------------------------- /.gitbook/assets/image (144).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (144).png -------------------------------------------------------------------------------- /.gitbook/assets/image (145).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (145).png -------------------------------------------------------------------------------- /.gitbook/assets/image (146).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (146).png -------------------------------------------------------------------------------- /.gitbook/assets/image (147).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (147).png -------------------------------------------------------------------------------- /.gitbook/assets/image (148).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (148).png -------------------------------------------------------------------------------- /.gitbook/assets/image (149).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (149).png -------------------------------------------------------------------------------- /.gitbook/assets/image (15).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (15).png -------------------------------------------------------------------------------- /.gitbook/assets/image (150).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (150).png -------------------------------------------------------------------------------- /.gitbook/assets/image (151).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (151).png -------------------------------------------------------------------------------- /.gitbook/assets/image (152).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (152).png -------------------------------------------------------------------------------- /.gitbook/assets/image (153).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (153).png -------------------------------------------------------------------------------- /.gitbook/assets/image (154).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (154).png -------------------------------------------------------------------------------- /.gitbook/assets/image (155).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (155).png -------------------------------------------------------------------------------- /.gitbook/assets/image (156).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (156).png -------------------------------------------------------------------------------- /.gitbook/assets/image (157).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (157).png -------------------------------------------------------------------------------- /.gitbook/assets/image (158).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (158).png -------------------------------------------------------------------------------- /.gitbook/assets/image (159).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (159).png -------------------------------------------------------------------------------- /.gitbook/assets/image (16).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (16).png -------------------------------------------------------------------------------- /.gitbook/assets/image (160).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (160).png -------------------------------------------------------------------------------- /.gitbook/assets/image (161).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (161).png -------------------------------------------------------------------------------- /.gitbook/assets/image (162).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (162).png -------------------------------------------------------------------------------- /.gitbook/assets/image (163).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (163).png -------------------------------------------------------------------------------- /.gitbook/assets/image (164).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (164).png -------------------------------------------------------------------------------- /.gitbook/assets/image (165).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (165).png -------------------------------------------------------------------------------- /.gitbook/assets/image (166).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (166).png -------------------------------------------------------------------------------- /.gitbook/assets/image (167).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (167).png -------------------------------------------------------------------------------- /.gitbook/assets/image (168).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (168).png -------------------------------------------------------------------------------- /.gitbook/assets/image (169).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (169).png -------------------------------------------------------------------------------- /.gitbook/assets/image (17).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (17).png -------------------------------------------------------------------------------- /.gitbook/assets/image (170).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (170).png -------------------------------------------------------------------------------- /.gitbook/assets/image (171).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (171).png -------------------------------------------------------------------------------- /.gitbook/assets/image (172).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (172).png -------------------------------------------------------------------------------- /.gitbook/assets/image (173).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (173).png -------------------------------------------------------------------------------- /.gitbook/assets/image (174).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (174).png -------------------------------------------------------------------------------- /.gitbook/assets/image (175).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (175).png -------------------------------------------------------------------------------- /.gitbook/assets/image (176).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (176).png -------------------------------------------------------------------------------- /.gitbook/assets/image (177).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (177).png -------------------------------------------------------------------------------- /.gitbook/assets/image (178).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (178).png -------------------------------------------------------------------------------- /.gitbook/assets/image (179).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (179).png -------------------------------------------------------------------------------- /.gitbook/assets/image (18).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (18).png -------------------------------------------------------------------------------- /.gitbook/assets/image (180).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (180).png -------------------------------------------------------------------------------- /.gitbook/assets/image (181).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (181).png -------------------------------------------------------------------------------- /.gitbook/assets/image (182).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (182).png -------------------------------------------------------------------------------- /.gitbook/assets/image (183).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (183).png -------------------------------------------------------------------------------- /.gitbook/assets/image (184).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (184).png -------------------------------------------------------------------------------- /.gitbook/assets/image (185).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (185).png -------------------------------------------------------------------------------- /.gitbook/assets/image (186).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (186).png -------------------------------------------------------------------------------- /.gitbook/assets/image (187).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (187).png -------------------------------------------------------------------------------- /.gitbook/assets/image (188).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (188).png -------------------------------------------------------------------------------- /.gitbook/assets/image (189).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (189).png -------------------------------------------------------------------------------- /.gitbook/assets/image (19).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (19).png -------------------------------------------------------------------------------- /.gitbook/assets/image (190).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (190).png -------------------------------------------------------------------------------- /.gitbook/assets/image (191).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (191).png -------------------------------------------------------------------------------- /.gitbook/assets/image (192).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (192).png -------------------------------------------------------------------------------- /.gitbook/assets/image (193).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (193).png -------------------------------------------------------------------------------- /.gitbook/assets/image (194).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (194).png -------------------------------------------------------------------------------- /.gitbook/assets/image (195).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (195).png -------------------------------------------------------------------------------- /.gitbook/assets/image (196).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (196).png -------------------------------------------------------------------------------- /.gitbook/assets/image (197).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (197).png -------------------------------------------------------------------------------- /.gitbook/assets/image (198).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (198).png -------------------------------------------------------------------------------- /.gitbook/assets/image (199).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (199).png -------------------------------------------------------------------------------- /.gitbook/assets/image (2).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (2).png -------------------------------------------------------------------------------- /.gitbook/assets/image (20).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (20).png -------------------------------------------------------------------------------- /.gitbook/assets/image (200).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (200).png -------------------------------------------------------------------------------- /.gitbook/assets/image (201).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (201).png -------------------------------------------------------------------------------- /.gitbook/assets/image (202).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (202).png -------------------------------------------------------------------------------- /.gitbook/assets/image (203).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (203).png -------------------------------------------------------------------------------- /.gitbook/assets/image (204).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (204).png -------------------------------------------------------------------------------- /.gitbook/assets/image (205).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (205).png -------------------------------------------------------------------------------- /.gitbook/assets/image (206).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (206).png -------------------------------------------------------------------------------- /.gitbook/assets/image (207).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (207).png -------------------------------------------------------------------------------- /.gitbook/assets/image (208).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (208).png -------------------------------------------------------------------------------- /.gitbook/assets/image (209).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (209).png -------------------------------------------------------------------------------- /.gitbook/assets/image (21).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (21).png -------------------------------------------------------------------------------- /.gitbook/assets/image (210).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (210).png -------------------------------------------------------------------------------- /.gitbook/assets/image (211).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (211).png -------------------------------------------------------------------------------- /.gitbook/assets/image (212).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (212).png -------------------------------------------------------------------------------- /.gitbook/assets/image (213).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (213).png -------------------------------------------------------------------------------- /.gitbook/assets/image (214).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (214).png -------------------------------------------------------------------------------- /.gitbook/assets/image (215).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (215).png -------------------------------------------------------------------------------- /.gitbook/assets/image (216).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (216).png -------------------------------------------------------------------------------- /.gitbook/assets/image (217).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (217).png -------------------------------------------------------------------------------- /.gitbook/assets/image (218).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (218).png -------------------------------------------------------------------------------- /.gitbook/assets/image (219).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (219).png -------------------------------------------------------------------------------- /.gitbook/assets/image (22).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (22).png -------------------------------------------------------------------------------- /.gitbook/assets/image (220).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (220).png -------------------------------------------------------------------------------- /.gitbook/assets/image (221).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (221).png -------------------------------------------------------------------------------- /.gitbook/assets/image (222).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (222).png -------------------------------------------------------------------------------- /.gitbook/assets/image (223).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (223).png -------------------------------------------------------------------------------- /.gitbook/assets/image (224).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (224).png -------------------------------------------------------------------------------- /.gitbook/assets/image (225).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (225).png -------------------------------------------------------------------------------- /.gitbook/assets/image (226).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (226).png -------------------------------------------------------------------------------- /.gitbook/assets/image (227).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (227).png -------------------------------------------------------------------------------- /.gitbook/assets/image (228).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (228).png -------------------------------------------------------------------------------- /.gitbook/assets/image (229).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (229).png -------------------------------------------------------------------------------- /.gitbook/assets/image (23).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (23).png -------------------------------------------------------------------------------- /.gitbook/assets/image (230).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (230).png -------------------------------------------------------------------------------- /.gitbook/assets/image (231).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (231).png -------------------------------------------------------------------------------- /.gitbook/assets/image (232).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (232).png -------------------------------------------------------------------------------- /.gitbook/assets/image (233).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (233).png -------------------------------------------------------------------------------- /.gitbook/assets/image (234).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (234).png -------------------------------------------------------------------------------- /.gitbook/assets/image (235).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (235).png -------------------------------------------------------------------------------- /.gitbook/assets/image (236).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (236).png -------------------------------------------------------------------------------- /.gitbook/assets/image (237).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (237).png -------------------------------------------------------------------------------- /.gitbook/assets/image (238).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (238).png -------------------------------------------------------------------------------- /.gitbook/assets/image (239).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (239).png -------------------------------------------------------------------------------- /.gitbook/assets/image (24).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (24).png -------------------------------------------------------------------------------- /.gitbook/assets/image (240).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (240).png -------------------------------------------------------------------------------- /.gitbook/assets/image (241).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (241).png -------------------------------------------------------------------------------- /.gitbook/assets/image (242).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (242).png -------------------------------------------------------------------------------- /.gitbook/assets/image (243).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (243).png -------------------------------------------------------------------------------- /.gitbook/assets/image (244).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (244).png -------------------------------------------------------------------------------- /.gitbook/assets/image (25).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (25).png -------------------------------------------------------------------------------- /.gitbook/assets/image (26).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (26).png -------------------------------------------------------------------------------- /.gitbook/assets/image (27).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (27).png -------------------------------------------------------------------------------- /.gitbook/assets/image (28).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (28).png -------------------------------------------------------------------------------- /.gitbook/assets/image (29).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (29).png -------------------------------------------------------------------------------- /.gitbook/assets/image (3).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (3).png -------------------------------------------------------------------------------- /.gitbook/assets/image (30).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (30).png -------------------------------------------------------------------------------- /.gitbook/assets/image (31).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (31).png -------------------------------------------------------------------------------- /.gitbook/assets/image (32).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (32).png -------------------------------------------------------------------------------- /.gitbook/assets/image (33).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (33).png -------------------------------------------------------------------------------- /.gitbook/assets/image (34).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (34).png -------------------------------------------------------------------------------- /.gitbook/assets/image (35).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (35).png -------------------------------------------------------------------------------- /.gitbook/assets/image (36).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (36).png -------------------------------------------------------------------------------- /.gitbook/assets/image (37).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (37).png -------------------------------------------------------------------------------- /.gitbook/assets/image (38).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (38).png -------------------------------------------------------------------------------- /.gitbook/assets/image (39).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (39).png -------------------------------------------------------------------------------- /.gitbook/assets/image (4).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (4).png -------------------------------------------------------------------------------- /.gitbook/assets/image (40).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (40).png -------------------------------------------------------------------------------- /.gitbook/assets/image (41).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (41).png -------------------------------------------------------------------------------- /.gitbook/assets/image (42).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (42).png -------------------------------------------------------------------------------- /.gitbook/assets/image (43).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (43).png -------------------------------------------------------------------------------- /.gitbook/assets/image (44).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (44).png -------------------------------------------------------------------------------- /.gitbook/assets/image (45).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (45).png -------------------------------------------------------------------------------- /.gitbook/assets/image (46).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (46).png -------------------------------------------------------------------------------- /.gitbook/assets/image (47).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (47).png -------------------------------------------------------------------------------- /.gitbook/assets/image (48).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (48).png -------------------------------------------------------------------------------- /.gitbook/assets/image (49).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (49).png -------------------------------------------------------------------------------- /.gitbook/assets/image (5).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (5).png -------------------------------------------------------------------------------- /.gitbook/assets/image (50).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (50).png -------------------------------------------------------------------------------- /.gitbook/assets/image (51).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (51).png -------------------------------------------------------------------------------- /.gitbook/assets/image (52).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (52).png -------------------------------------------------------------------------------- /.gitbook/assets/image (53).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (53).png -------------------------------------------------------------------------------- /.gitbook/assets/image (54).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (54).png -------------------------------------------------------------------------------- /.gitbook/assets/image (55).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (55).png -------------------------------------------------------------------------------- /.gitbook/assets/image (56).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (56).png -------------------------------------------------------------------------------- /.gitbook/assets/image (57).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (57).png -------------------------------------------------------------------------------- /.gitbook/assets/image (58).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (58).png -------------------------------------------------------------------------------- /.gitbook/assets/image (59).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (59).png -------------------------------------------------------------------------------- /.gitbook/assets/image (6).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (6).png -------------------------------------------------------------------------------- /.gitbook/assets/image (60).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (60).png -------------------------------------------------------------------------------- /.gitbook/assets/image (61).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (61).png -------------------------------------------------------------------------------- /.gitbook/assets/image (62).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (62).png -------------------------------------------------------------------------------- /.gitbook/assets/image (63).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (63).png -------------------------------------------------------------------------------- /.gitbook/assets/image (64).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (64).png -------------------------------------------------------------------------------- /.gitbook/assets/image (65).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (65).png -------------------------------------------------------------------------------- /.gitbook/assets/image (66).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (66).png -------------------------------------------------------------------------------- /.gitbook/assets/image (67).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (67).png -------------------------------------------------------------------------------- /.gitbook/assets/image (68).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (68).png -------------------------------------------------------------------------------- /.gitbook/assets/image (69).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (69).png -------------------------------------------------------------------------------- /.gitbook/assets/image (7).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (7).png -------------------------------------------------------------------------------- /.gitbook/assets/image (70).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (70).png -------------------------------------------------------------------------------- /.gitbook/assets/image (71).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (71).png -------------------------------------------------------------------------------- /.gitbook/assets/image (72).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (72).png -------------------------------------------------------------------------------- /.gitbook/assets/image (73).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (73).png -------------------------------------------------------------------------------- /.gitbook/assets/image (74).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (74).png -------------------------------------------------------------------------------- /.gitbook/assets/image (75).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (75).png -------------------------------------------------------------------------------- /.gitbook/assets/image (76).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (76).png -------------------------------------------------------------------------------- /.gitbook/assets/image (77).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (77).png -------------------------------------------------------------------------------- /.gitbook/assets/image (78).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (78).png -------------------------------------------------------------------------------- /.gitbook/assets/image (79).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (79).png -------------------------------------------------------------------------------- /.gitbook/assets/image (8).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (8).png -------------------------------------------------------------------------------- /.gitbook/assets/image (80).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (80).png -------------------------------------------------------------------------------- /.gitbook/assets/image (81).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (81).png -------------------------------------------------------------------------------- /.gitbook/assets/image (82).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (82).png -------------------------------------------------------------------------------- /.gitbook/assets/image (83).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (83).png -------------------------------------------------------------------------------- /.gitbook/assets/image (84).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (84).png -------------------------------------------------------------------------------- /.gitbook/assets/image (85).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (85).png -------------------------------------------------------------------------------- /.gitbook/assets/image (86).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (86).png -------------------------------------------------------------------------------- /.gitbook/assets/image (87).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (87).png -------------------------------------------------------------------------------- /.gitbook/assets/image (88).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (88).png -------------------------------------------------------------------------------- /.gitbook/assets/image (89).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (89).png -------------------------------------------------------------------------------- /.gitbook/assets/image (9).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (9).png -------------------------------------------------------------------------------- /.gitbook/assets/image (90).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (90).png -------------------------------------------------------------------------------- /.gitbook/assets/image (91).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (91).png -------------------------------------------------------------------------------- /.gitbook/assets/image (92).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (92).png -------------------------------------------------------------------------------- /.gitbook/assets/image (93).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (93).png -------------------------------------------------------------------------------- /.gitbook/assets/image (94).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (94).png -------------------------------------------------------------------------------- /.gitbook/assets/image (95).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (95).png -------------------------------------------------------------------------------- /.gitbook/assets/image (96).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (96).png -------------------------------------------------------------------------------- /.gitbook/assets/image (97).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (97).png -------------------------------------------------------------------------------- /.gitbook/assets/image (98).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (98).png -------------------------------------------------------------------------------- /.gitbook/assets/image (99).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image (99).png -------------------------------------------------------------------------------- /.gitbook/assets/image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyStudy/PHP-7-Real-World-Application-Development/3a309164d354f61bfe9206be6bcabf813a195e45/.gitbook/assets/image.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 前言 2 | 3 | ## PHP 7:真实世界的应用开发(中文翻译) 4 | 5 | * 作者:[Doug Bierer](https://learning.oreilly.com/search/?query=author%3A%22Doug%20Bierer%22&sort=relevance&highlight=true), [Altaf Hussain](https://learning.oreilly.com/search/?query=author%3A%22Altaf%20Hussain%22&sort=relevance&highlight=true), [Branko Ajzele](https://learning.oreilly.com/search/?query=author%3A%22Branko%20Ajzele%22&sort=relevance&highlight=true) 6 | * 原书名称:《[PHP 7: Real World Application Development](https://www.packtpub.com/php-7-real-world-application-development)》 7 | * 译者:金弘扬([ganymedenil@gmail.com](mailto:ganymedenil@gmail.com)) 8 | * Gitbook地址:[PHP 7:真实世界的应用开发](https://ganymedenil.gitbook.io/php-7/) 9 | * github:[https://github.com/AnyStudy/PHP-7-Real-World-Application-Development](https://github.com/AnyStudy/PHP-7-Real-World-Application-Development) 10 | 11 | 推荐使用 Gitbook 以获取最佳阅读体验。 12 | 13 | ## 译序 14 | 15 | 作为一个使用了php多年的程序员,公司项目也经历过5到7的升级,期间项目也出现过一些因为php7功能与php5 不一致导致的bug。我一直在寻找一本能详细介绍 php 7 新特性与功能的书,后来找到了这本,虽然这本书发布到现在已经差不多4年了,但是对于想详细了解php7的朋友来说里面所讲述的内容我认为还是很有价值的。并且本书作者的一些观点我也非常认同,就想着希望能让更多人看到,趁着十一假期有时间想试着翻译一下本书。本书实际是三本独立的书,但如果单独看这三本都感觉缺点什么,把这三本书合并为一本我感觉就很相辅相成。本书的模块2也就是《高性能 php 7》部分已经由吕毅老师翻译,本人就不再对本模块进行翻译。如果我的翻译能帮助到大家,也是我最大到荣幸。 16 | 17 | ## 前言 18 | 19 | PHP 7 在开源社区掀起了一场风暴,它打破了之前版本的速度记录,也重新引起了人们对它的关注。从最根本的意义上讲,核心工程团队已经对它进行了重大重写,但仍能保持高度的向后兼容性。PHP是一门开发Web应用的好语言。它本质上是一类服务器端脚本语言,也用于通用编程。PHP 7是最新的版本,提供了主要的向后兼容性突破,并专注于提高性能和速度。这意味着你可以通过多线程网络服务器,用低成本的硬件和服务器维持网站的高流量。 20 | 21 | ### 这条学习之路都涵盖了什么 22 | 23 | 模块1,PHP 7 编程指南,本模块以 PHP 7 为中心,展示了中高级的PHP技术。每个示例都是为了解决像您这样的 PHP 开发人员每天面临的实际问题。其中还介绍了只有在 PHP 7 中才有的,新的编写 PHP 代码的方法。此外,我们还讨论了向后兼容性中断的问题,并为您提供了大量指导,告诉您何时何地需要修改 PHP 5 代码,以便在 PHP 7 下运行时产生正确的结果。本模块还包含了最新的 PHP 7.x 特性。在本模块结束时,您将具备为您的网站和企业提供高效应用程序所需的工具和技能。 24 | 25 | 模块2,学习 PHP 7 高性能,该模块是 PHP 7 的快速入门,这将提高您的生产力和编码技能。所涉及的概念将使您作为一个PHP程序员,提高你的应用程序的性能标准。我们将向您介绍 PHP 7 中的新特性,然后介绍 PHP 7 中面向对象编程(OOP)的概念。接下来,我们将阐明如何提高 PHP 7 应用程序的性能和数据库性能。通过这个模块,您将能够使用模块中讨论的各种基准测试工具来提高程序的性能。最后,模块讨论了 PHP 编程中的一些最佳实践,以帮助你提高代码的质量。 26 | 27 | 模块3,用 PHP 7 更新旧版应用程序,此模块将向您展示如何通过提取和替换旧版组件,从实践和技术上而不是在使用框架和库之类的工具方面对应用程序进行升级。 我们将采用循序渐进的方法,有条不紊地缓慢前进,从根本上改善您的应用程序。我们将向您展示依赖注入是如何替换新的和全局依赖的。我们还将向您展示如何将表示逻辑改为视图文件,将动作逻辑改为控制器。此外,我们将使您的应用程序始终保持运行状态。在这个过程中,每一个完成的步骤都会让您的代码库以更高的质量完全正常运行。当我们完成后,您将能够像风一样轻而易举地通过您的代码。您的代码将是自动加载、依赖注入、单元测试、层级分离和前端控制。我们将添加到您的应用程序中的大多数非常有限的代码都是针对这个模块的。我们将以程序员的身份提高自己,并提高传统应用程序的质量。 28 | 29 | ### 你在这条学习之路上需要什么 30 | 31 | #### 模块1 32 | 33 | 要成功地实现本模块中介绍的示例,你只需要一台计算机,100MB 的额外磁盘空间,和一个文本或代码编辑器(不是文字处理器!)。第一章将介绍如何设置 PHP 7 开发环境。拥有一个 Web 服务器是可选的,因为 PHP 7 包含一个开发 Web 服务器。不需 Internet 连接,但下载代码(如 PSR-7 接口集)和查看 PHP 7.x 文档可能会需要。 34 | 35 | #### 模块2 36 | 37 | 任何符合运行以下软件最新版本的硬件规格,应该都足以通过本模块。 38 | 39 | * 操作系统: Debian 或 Ubuntu 40 | * 软件: NGINX、PHP 7、 MySQL、 PerconaDB、 Redis、 Memcached、 Xdebug、Apache JMeter、 ApacheBench、Siege 和 Git 41 | 42 | #### 模块3 43 | 44 | 您需要参考本模块的“第二章,先决条件“来了解本模块所需的基本硬件和软件要求。本章将详细描述这些要求。 45 | 46 | ### 这条路是为谁而设 47 | 48 | 如果您是一个有抱负的Web开发人员,移动应用开发人员或后端程序员,并且具有PHP编程的基本经验并希望开发对性能至关重要的应用程序,那么这个课程是为你准备的。它将使您的PHP编程技能更上一层楼。 49 | 50 | ### 支持 51 | 52 | 课程的代码包也托管在github上 [https://GitHub.com/packtpublishing/php-7-be-pro-at-applications-development](https://GitHub.com/packtpublishing/php-7-be-pro-at-applications-development) 。 53 | 54 | ## 法律申明 55 | 56 | 译者纯粹出于**学习目的**与**个人兴趣**翻译本书,不追求任何经济利益。 57 | 58 | 译者保留对此版本译文的署名权,其他权利以原作者和出版社的主张为准。 59 | 60 | 本译文只供学习研究参考之用,不得公开传播发行或用于商业用途。有能力阅读英文书籍者请购买正版支持。 61 | 62 | ### LICENSE 63 | 64 | CC-BY 4.0 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /mo-kuai-san.md: -------------------------------------------------------------------------------- 1 | # 模块三 2 | 3 | -------------------------------------------------------------------------------- /mo-kuai-san/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: 用PHP 7进行模块化编程 3 | --- 4 | 5 | # 模块三 6 | 7 | 用PHP 7进行模块化编程 8 | 9 | 利用模块化编程的力量来提高代码的可读性、可维护性和可测试性。 10 | 11 | -------------------------------------------------------------------------------- /mo-kuai-san/gof-she-ji-mo-shi/gai-yao.md: -------------------------------------------------------------------------------- 1 | # 小结 2 | 3 | 设计模式是开发人员的一种通用的高级语言。它们使团队成员之间能够以一种快捷的方式交流应用设计。了解如何识别和实现设计模式,将我们的关注点转移到业务需求解决上,而不是在代码层面上修修补补如何将我们的解决方案粘合在一起。 4 | 5 | 编码,就像大多数手工制作的学科一样,是那种你付出多少就能得到多少的学科。虽然实现一些设计模式需要一定的时间,但在更大的项目上缺乏这样做很可能会在未来以这样或那样的方式赶上我们。与 "是否使用框架 "的争论类似,实现正确的设计模式会影响我们代码的可扩展性、可重用性、适应性和可维护性。因此,使它更具有未来性。 6 | 7 | 向前看,在下一章中,我们将研究SOLID设计原则以及它们在软件开发过程中的作用。 8 | 9 | -------------------------------------------------------------------------------- /mo-kuai-san/mo-kuai-hua-wang-dian-ying-yong-de-xu-qiu-gui-fan/README.md: -------------------------------------------------------------------------------- 1 | # 模块化网店应用的需求规范 2 | 3 | 从零开始构建一个软件应用程序需要多种技能,因为它不仅仅是写下代码。写下功能需求和勾画线框通常是这个过程中的第一步,特别是当我们正在为客户项目工作时。这些步骤通常是由开发人员以外的人完成的,因为它们需要对客户的商业案例、用户行为等有一定的洞察力。作为一个较大的开发团队的一部分,意味着我们作为开发人员,通常会得到需求、设计和线框,然后根据它们开始编码。自己交付项目,使得我们很想跳过这些步骤,独自开始动手写代码。更多的时候,这是一种没有成效的做法。放下功能需求和几个线框是一个值得了解和遵循的技能,即使自己只是一个开发人员。 4 | 5 | 在本章的后面,我们将介绍一个高级应用需求,以及一个粗略的线框。 6 | 7 | 在本章中,我们将涉及以下主题: 8 | 9 | * 确定应用需求 10 | * 线框设计 11 | * 定义技术栈 12 | * Symfony 框架 13 | * Foundation 框架 14 | 15 | ## 确定应用需求 16 | 17 | 我们需要建立一个简单的,但响应的网店应用程序。为了做到这一点,我们需要列出一些基本需求。目前我们感兴趣的需求类型是那些触及用户和系统之间的交互的需求。在用户使用方面,指定需求的两种最常见的技术是用例和用户故事。用户故事是一种不那么正式但足够描述性的方式来概述这些需求。使用用户故事,我们封装了这里提到的客户和店长的行动。 18 | 19 | 客户应该能够做到以下几点: 20 | 21 | * 浏览静态信息页面(关于我们,客户服务) 22 | * 通过联系表格与店主取得联系 23 | * 浏览店铺类别 24 | * 查看产品详情(价格、说明) 25 | * 查看产品图片的大视图(放大) 26 | * 查看正在销售的商品 27 | * 查看畅销产品 28 | * 将产品添加到购物车中 29 | * 创建一个客户账户 30 | * 更新客户账户信息 31 | * 找回丢失的密码 32 | * 结账 33 | * 查看订单总成本 34 | * 在几种付款方式中选择 35 | * 在几种运输方式中选择 36 | * 下单后收到电子邮件通知 37 | * 检查订单状态 38 | * 取消订单 39 | * 查看订单历史 40 | 41 | 一个店长应该能够做到以下几点: 42 | 43 | * 创建一个产品(至少有以下属性:标题、价格、sku、url-key、描述、数量、类别和图片) 44 | * 上传产品图片 45 | * 更新和删除产品 46 | * 创建一个类别(至少有以下属性:标题、url-key、描述和图片) 47 | * 上传图片到一个类别 48 | * 更新和删除一个类别 49 | * 如果有新的销售订单被创建,会收到通知 50 | * 如果有新的销售订单被取消,会收到通知 51 | * 按状态查看现有销售订单 52 | * 更新订单状态 53 | * 停用客户账户 54 | * 删除客户账户 55 | 56 | 用户故事是记录应用程序需求的便捷高级方法。作为一种敏捷的开发模式,尤其有用。 57 | 58 | -------------------------------------------------------------------------------- /mo-kuai-san/mo-kuai-hua-wang-dian-ying-yong-de-xu-qiu-gui-fan/ding-yi-ji-shu-zhan.md: -------------------------------------------------------------------------------- 1 | # 定义技术栈 2 | 3 | 一旦需求和线框设定好了,我们就可以把注意力集中到技术栈的选择上。在第1章,生态系统概述中,我们简要介绍了几个最流行的PHP框架,指出了它们的优势。在这种情况下,选择合适的框架更多的是一个偏好的问题,因为大多数应用需求可以很容易地通过这些框架中的任何一个来满足。然而,我们的选择是Symfony。除了PHP框架之外,我们仍然需要一个CSS框架来在客户端的浏览器内提供一些结构、样式和响应性。由于本书的重点是PHP技术,所以我们就选择Foundation CSS框架来完成这个任务吧。 4 | 5 | ## Symfony 框架 6 | 7 | Symfony框架对我们的应用来说是一个不错的选择。它是一个企业级的框架,已经存在了很多年,并且有非常好的文档和支持。它可以从官方的[http://symfony.com](http://symfony.com) 页面下载,如图所示。 8 | 9 | ![](../../.gitbook/assets/image%20%28168%29.png) 10 | 11 | 使用Symfony作为我们技术栈的好处有很多。该框架提供了强大和完善的文档。 12 | 13 | * 控制器 14 | * 路由 15 | * ORM\(通过 Doctrine\) 16 | * 表单 17 | * 验证 18 | * 安全 19 | 20 | 这些都是我们应用所需要的基本功能。尤其是ORM,在快速开发应用的过程中起到了重要的作用。不用担心编码的问题,CRUD的每一个环节都能让开发速度提升一到两个百分点。在这方面,Symfony的伟大之处在于,它可以通过执行以下两个简单的命令,自动生成实体和围绕实体的CRUD动作。 21 | 22 | ```bash 23 | php bin/console doctrine:generate:entity 24 | php app/console generate:doctrine:crud 25 | ``` 26 | 27 | 通过这样做,Symfony生成实体模型和必要的控制器,使我们能够执行以下操作。 28 | 29 | * 列出所有记录 30 | * 展示一条通过主键查询的记录 31 | * 创建一个新记录 32 | * 编辑现有记录 33 | * 删除现有记录 34 | 35 | 基本上,我们免费得到了一个最小的店长界面。仅此一项就涵盖了店长角色设置的大部分CRUD相关需求。然后,我们可以轻松地修改生成的模板,进一步整合其余功能。 36 | 37 | 除此之外,安全组件还提供了认证和授权,我们可以用来满足客户和店长的登录。所以,店长将是一个固定的、预先创建的用户,连接在Symfony的防火墙上,是唯一一个可以访问CRUD控制器操作的用户。 38 | 39 | ## Foundation 框架 40 | 41 | 在Zurb公司的支持下,Foundation框架为现代响应式Web应用做了一个很好的选择。我们可以说它是一个企业级框架,提供了一个HTML、CSS和JavaScript的集合,我们可以在此基础上进行构建。它可以从官方的[http://foundation.zurb.com](http://foundation.zurb.com) 页面下载,如图所示。 42 | 43 | ![](../../.gitbook/assets/image%20%28171%29.png) 44 | 45 | Foundation 提供了三种使用场景的支持: 46 | 47 | * Foundation for sites 48 | * Foundation for e-mail 49 | * Foundation for apps 50 | 51 | 我们感兴趣的是网站版本。除了一般的样式,Foundation for sites还提供了大量的控件、导航元素、容器、媒体元素和插件。这些在我们的应用中会特别有用,比如标题菜单、分类产品列表、响应式购物车表格等等。 52 | 53 | Foundation是作为一个移动优先的框架而构建的,我们首先为小屏幕编写代码,然后在大屏幕上继承这些风格。它默认的12列网格系统使我们能够快速、轻松地创建强大的多设备布局。 54 | 55 | 我们将简单地使用Foundation来为我们的应用程序提供结构、一些基本的样式和响应能力,而不需要自己编写一行CSS。仅此一点,就能让我们的应用在视觉上有足够的美感,在移动和桌面屏幕上都能使用,同时我们的大部分编码技能仍然集中在后端事物上。 56 | 57 | 除了提供强大的功能外,Foundation背后的公司还提供了优质的技术支持。虽然作为本书的一部分,我们不会需要它,但这些东西在选择应用框架时建立了信心。 58 | 59 | -------------------------------------------------------------------------------- /mo-kuai-san/mo-kuai-hua-wang-dian-ying-yong-de-xu-qiu-gui-fan/gai-yao.md: -------------------------------------------------------------------------------- 1 | # 小结 2 | 3 | 创建网络应用程序是一项繁琐而耗时的任务,网络商店可能是最强大和最密集的应用类型之一,因为它们包含了大量的功能。在交付最终产品的过程中涉及到许多组件;从数据库、服务器端(PHP)代码到客户端(HTML、CSS和JavaScript)代码。在本章中,我们首先定义了一些基本的用户故事,进而定义了我们的小型网络商店的高级应用需求。在其中加入线框图,帮助我们将面向客户的界面可视化,而店长界面则要由框架提供开箱即用。 4 | 5 | 我们进一步光顾了两个最流行的支持模块化应用设计的框架。我们将注意力转向了作为服务器端技术的Symfony和作为客户端响应式框架的Foundation。 6 | 7 | 往后,在下一章中,我们将更深入地了解Symfony。除了是一套可重用的组件外,Symfony也是最强大和最流行的全栈PHP框架之一。因此,它是快速开发Web应用的一个有趣的选择。 8 | 9 | -------------------------------------------------------------------------------- /mo-kuai-san/mo-kuai-hua-wang-dian-ying-yong-de-xu-qiu-gui-fan/xian-kuang-she-ji.md: -------------------------------------------------------------------------------- 1 | # 线框设计 2 | 3 | 有了用户故事的铺垫,让我们把重点转移到实际的线框设计上来。出于我们稍后会讲到的原因,我们的线框工作将围绕客户的角度进行。 4 | 5 | 目前有很多线框工具,有免费的也有商业的。一些商业工具,如https://ninjamock.com,我们将在我们的例子中使用,仍然提供免费计划。这对于个人项目来说是非常方便的,因为它为我们节省了很多时间。 6 | 7 | 每一个网络应用的起点都是它的主页。下面的线框说明了我们网店应用的主页。 8 | 9 | ![](../../.gitbook/assets/image%20%28160%29.png) 10 | 11 | 在这里我们可以看到决定页面结构的几个部分。头部由logo、分类菜单和用户菜单组成。需求中没有提到任何关于类别结构的内容,而我们正在构建一个简单的网店应用,所以我们将坚持使用扁平化的类别结构,没有任何子类别。用户菜单最初将显示注册和登录链接,直到用户真正登录,在这种情况下,菜单将发生变化,如以下线框所示。内容区域充满了畅销商品和促销商品,每个商品都定义了图片、标题、价格和添加到购物车按钮。页脚区域包含了大部分静态内容页面的链接,以及一个联系我们页面。 12 | 13 | 下面的线框说明了我们网店应用的分类页面。 14 | 15 | ![](../../.gitbook/assets/image%20%28190%29.png) 16 | 17 | 整个网站的页眉和页脚区域在概念上保持不变。内容区域现在已改为列出任何给定类别内的产品。单个产品区域的呈现方式与主页上相同。类别名称和图片呈现在产品列表上方。类别图片的宽度给出了一些提示,说明我们应该准备什么类型的图片并上传到我们的类别中。 18 | 19 | 下面的线框说明了我们网店应用的产品页面。 20 | 21 | ![](../../.gitbook/assets/image%20%28205%29.png) 22 | 23 | 现在,这里的内容区域改变为列出单个产品信息。我们可以看到一个大的图片占位符、标题、sku、库存状态、价格、数量字段、添加到购物车按钮和产品描述正在呈现。当商品可以购买时,要显示IN STOCK信息,当商品不再有货时,要显示OUT OF STOCK信息。这要和产品数量属性相关。我们还需要牢记 "以大视角(缩放)查看产品图片 "的要求,点击图片会放大图片。 24 | 25 | 下面的线框说明了我们网店应用的注册页面。 26 | 27 | ![](../../.gitbook/assets/image%20%28157%29.png) 28 | 29 | 现在这里的内容区会改变,呈现一个注册表。我们有很多方法可以实现注册系统。更多的时候,在注册屏幕上询问的信息量是最小的,因为我们想让用户尽快进入。然而,让我们在注册屏幕上尝试获取更完整的用户信息。我们不仅要求用户提供电子邮件和密码,还要求用户提供整个地址信息。 30 | 31 | 下面的线框说明了我们网店应用的登录页面。 32 | 33 | ![](../../.gitbook/assets/image%20%28200%29.png) 34 | 35 | 现在这里的内容区域改变为呈现客户登录和忘记密码的表单。我们为用户提供登录时的Email和密码字段,或者在密码重置操作时只提供Email字段。 36 | 37 | 下面的线框说明了我们网店应用的客户账户页面。 38 | 39 | ![](../../.gitbook/assets/image%20%28165%29.png) 40 | 41 | 现在这里的内容区域变为呈现客户账户区域,只有登录的客户才能看到。在这里我们看到一个屏幕,主要有两个信息。客户信息是一个,订单历史是另一个。客户可以在这个屏幕上修改自己的邮箱、密码等地址信息。此外,客户还可以查看、取消、打印之前的所有订单。我的订单表从上到下,从最新到最旧列出订单。虽然用户故事没有指定,但订单取消应该只对待定订单有效。这一点我们会在后面详细介绍。 42 | 43 | 这也是用户登录时显示用户菜单状态的第一屏。我们可以看到一个下拉菜单,显示了用户的全名、我的账户和注销链接。就在它的旁边,我们有购物车(%s)链接,这是为了列出购物车中的确切数量。 44 | 45 | 下面的线框说明了我们的网店应用的结账购物车页面。 46 | 47 | ![](../../.gitbook/assets/image%20%28187%29.png) 48 | 49 | 现在这里的内容区域会改变,以呈现购物车的当前状态。如果客户在购物车中添加了任何产品,它们将在这里列出。每个项目应该列出产品的标题、单个价格、添加的数量和小计。顾客应该能够改变数量,并按更新购物车按钮来更新购物车的状态。如果提供的数量为0,点击更新购物车按钮将从购物车中删除该商品。购物车的数量应该在任何时候都反映出标题菜单购物车(%s)链接的状态。屏幕的右侧显示了当前订单总价值的快速摘要,旁边还有一个大而清晰的 "去结账 "按钮。 50 | 51 | 下面的线框说明了我们的网店应用的结账购物车发货页面。 52 | 53 | ![](../../.gitbook/assets/image%20%28184%29.png) 54 | 55 | 这里的内容区域现在改变为呈现结账过程的第一步,即收集运输信息。未登录的客户应该无法访问此屏幕。客户可以在这里向我们提供他们的地址详细信息,同时选择送货方式。送货方式区域列出了几种送货方式。在右侧,显示了可折叠的订单摘要部分,列出了当前购物车中的项目。在它的下方,我们有购物车的小计值和一个大大的清晰的下一步按钮。只有在提供了所有所需信息后,下一步按钮才会触发,在这种情况下,它应该把我们带到结账车付款页面的付款信息。 56 | 57 | 下面的线框说明了我们的网店应用的结账车支付页面。 58 | 59 | ![](../../.gitbook/assets/image%20%28203%29.png) 60 | 61 | 这里的内容区域现在改变为呈现结账流程的第二步,即付款信息收集。未登录的客户不应访问此屏幕。客户会看到一个可用的支付方式列表。为了应用的简单性,我们将只关注统一/固定的支付方式,而不是像PayPal或Stripe这样的强大支付方式。在屏幕的右侧,我们可以看到一个可折叠的订单摘要部分,列出购物车中的当前项目。在它的下方,我们有订单总数部分,分别列出了购物车小计、标准送货、订单总数,以及一个大大的清晰的下单按钮。只有在提供了所有所需信息的情况下,下单按钮才会触发,在这种情况下,它应该把我们带到结账成功的页面。 62 | 63 | 下面的线框说明了我们的网络商店应用程序的结账成功页面。 64 | 65 | ![](../../.gitbook/assets/image%20%28175%29.png) 66 | 67 | 现在这里的内容区域会改变,输出结账成功的信息。显然,这个页面只有刚刚完成结账过程的登录客户才能看到。订单号是可以点击的,并链接到 "我的账户 "区域,关注具体订单。到了这个页面,客户和店长都应该会收到一封通知邮件,按照订单下达后获得邮件通知和如果新的销售订单已经创建就会被通知的要求。 68 | 69 | 到此,我们面向客户的线框就结束了。 70 | 71 | 关于店长用户故事需求,我们暂时只定义一个登陆管理界面,如下截图所示。 72 | 73 | ![](../../.gitbook/assets/image%20%28179%29.png) 74 | 75 | 后面使用框架,我们将得到一个完整的自动生成的CRUD接口,用于多个Add New和List & Manage链接。对这个界面及其链接的访问将由框架的安全组件控制,因为这个用户不会是客户或数据库中的任何用户。 76 | 77 | 此外,在下面的章节中,我们将把我们的应用程序分成几个模块。在这样的设置中,每个模块将拥有单独的功能,负责客户、目录、结账和其他需求。 78 | 79 | -------------------------------------------------------------------------------- /mo-kuai-san/solid-she-ji-yuan-ze/README.md: -------------------------------------------------------------------------------- 1 | # SOLID 设计原则 2 | 3 | 构建模块化软件需要很强的类设计知识。有很多指南,涉及到我们对类的命名方式,类应该有多少个变量,方法的大小应该是多少等等。PHP生态系统设法将这些打包成了官方的PSR标准,更准确地说,是**PSR-1:基本编码标准**和**PSR-2:编码风格指南**。这些都是一般的编程指南,让我们的代码可读、可理解、可维护。 4 | 5 | 除了编程指南外,在类设计过程中,我们还可以应用更具体的设计原则。关于解决低耦合、高内聚和强封装的概念。我们把它们称为SOLID设计原则,这个术语是Robert Cecil Martin在2000年初创造的。 6 | 7 | SOLID是以下五个原则的缩写: 8 | 9 | * S:单一职责原则\(SRP\) 10 | * O:开闭原则\(OCP\) 11 | * L:里氏替换原则\(LSP\) 12 | * I: 接口隔离原则\(ISP\) 13 | * D:依赖反转原则\(DIP\) 14 | 15 | SOLID原则的概念已经有十多年的历史了,但它远远没有过时,因为它们是好的类设计的核心。在本章中,我们将研究这些原则中的每一条,通过观察一些明显违反原则的行为来了解它们。 16 | 17 | 在本章中,我们将涉及以下主题: 18 | 19 | * 单一职责原则 20 | * 开闭原则 21 | * 里氏替换原则 22 | * 接口隔离原则 23 | * 依赖反转原则 24 | 25 | ## 单一职责原则 26 | 27 | 单一职责原则处理的是试图做得太多的类。这里的职责是指改变的原因。按照罗伯特-C-马丁的定义。 28 | 29 | > _一个类仅有一个引起它变化的原因_ 30 | 31 | 下面是一个违反SRP的类的例子: 32 | 33 | ```php 34 | class Ticket { 35 | const SEVERITY_LOW = 'low'; 36 | const SEVERITY_HIGH = 'high'; 37 | // ... 38 | protected $title; 39 | protected $severity; 40 | protected $status; 41 | protected $conn; 42 | 43 | public function __construct(\PDO $conn) { 44 | $this->conn = $conn; 45 | } 46 | 47 | public function setTitle($title) { 48 | $this->title = $title; 49 | } 50 | 51 | public function setSeverity($severity) { 52 | $this->severity = $severity; 53 | } 54 | 55 | public function setStatus($status) { 56 | $this->status = $status; 57 | } 58 | 59 | private function validate() { 60 | // Implementation... 61 | } 62 | 63 | public function save() { 64 | if ($this->validate()) { 65 | // Implementation... 66 | } 67 | } 68 | 69 | } 70 | 71 | // Client 72 | $conn = new PDO(/* ... */); 73 | $ticket = new Ticket($conn); 74 | $ticket->setTitle('Checkout not working!'); 75 | $ticket->setStatus(Ticket::STATUS_OPEN); 76 | $ticket->setSeverity(Ticket::SEVERITY_HIGH); 77 | $ticket->save(); 78 | ``` 79 | 80 | `Ticket`类处理的是 `ticket` 实体的验证和保存到数据库。这两个职责是它改变的两个原因。每当关于票据验证,或者关于票据保存的需求发生变化时,就必须修改`Ticket` 类。为了解决这里的SRP违规,我们可以使用辅助类和接口来分割职责。 81 | 82 | 下面是一个重构后的实现实例,符合SRP的要求。 83 | 84 | ```php 85 | interface KeyValuePersistentMembers { 86 | public function toArray(); 87 | } 88 | 89 | class Ticket implements KeyValuePersistentMembers { 90 | const STATUS_OPEN = 'open'; 91 | const SEVERITY_HIGH = 'high'; 92 | //... 93 | protected $title; 94 | protected $severity; 95 | protected $status; 96 | 97 | public function setTitle($title) { 98 | $this->title = $title; 99 | } 100 | 101 | public function setSeverity($severity) { 102 | $this->severity = $severity; 103 | } 104 | 105 | public function setStatus($status) { 106 | $this->status = $status; 107 | } 108 | 109 | public function toArray() { 110 | // Implementation... 111 | } 112 | } 113 | 114 | class EntityManager { 115 | protected $conn; 116 | 117 | public function __construct(\PDO $conn) { 118 | $this->conn = $conn; 119 | } 120 | 121 | public function save(KeyValuePersistentMembers $entity) 122 | { 123 | // Implementation... 124 | } 125 | } 126 | 127 | class Validator { 128 | public function validate(KeyValuePersistentMembers $entity) { 129 | // Implementation... 130 | } 131 | } 132 | 133 | // Client 134 | $conn = new PDO(/* ... */); 135 | 136 | $ticket = new Ticket(); 137 | $ticket->setTitle('Payment not working!'); 138 | $ticket->setStatus(Ticket::STATUS_OPEN); 139 | $ticket->setSeverity(Ticket::SEVERITY_HIGH); 140 | 141 | $validator = new Validator(); 142 | 143 | if ($validator->validate($ticket)) { 144 | $entityManager = new EntityManager($conn); 145 | $entityManager->save($ticket); 146 | } 147 | ``` 148 | 149 | 在这里,我们引入了一个简单的`KeyValuePersistentMembers`接口,它只有一个`toArray`方法,然后与`EntityManager`和`Validator`类一起使用,现在这两个类都只承担一个职责。`Ticket`类变成了一个简单的数据持有模型,而客户端现在控制实例化、验证和保存为三个不同的步骤。虽然这肯定不是如何分离职责的通用公式,但它确实提供了一个简单而清晰的例子。 150 | 151 | 以单一职责原则为前提进行设计,可以产生更小的类,具有更高的可读性和更容易测试代码。 152 | 153 | -------------------------------------------------------------------------------- /mo-kuai-san/solid-she-ji-yuan-ze/gai-yao.md: -------------------------------------------------------------------------------- 1 | # 小结 2 | 3 | 谈到模块化开发,可扩展性是需要不断思考的问题。如果编写的代码把自己锁死,很可能导致将来无法与其他项目或库集成。虽然SOLID设计原则对于某些部分来说可能显得有些过激,但积极应用这些原则很可能会带来易于维护和长期扩展的组件。 4 | 5 | 拥抱SOLID原则进行类设计,为我们的代码为未来的变化做好准备。它通过在我们的类中本地化和最小化这些变化来做到这一点,因此任何使用它的集成都不会感受到特别大的变化。 6 | 7 | 今后,在下一章中,我们将研究定义我们的应用规范,我们将在所有其他章节中建立这个规范。 8 | 9 | -------------------------------------------------------------------------------- /mo-kuai-san/solid-she-ji-yuan-ze/jie-kou-ge-li-yuan-ze.md: -------------------------------------------------------------------------------- 1 | # 接口隔离原则 2 | 3 | 接口隔离原则指出,客户应该只实现他们实际使用的接口。他们不应该被强迫实现他们不使用的接口。根据维基百科上的定义: 4 | 5 | > _多个客户端专用接口比一个通用接口要好_ 6 | 7 | 这意味着,我们应该把大而肥的接口分成若干个小而轻的接口,把它隔离开来,让小的接口以方法组为基础,每个方法服务于一个特定的功能。 8 | 9 | 我们来看看下面这个违反ISP的例子: 10 | 11 | ```php 12 | interface Appliance { 13 | public function powerOn(); 14 | public function powerOff(); 15 | public function bake(); 16 | public function mix(); 17 | public function wash(); 18 | 19 | } 20 | 21 | class Oven implements Appliance { 22 | public function powerOn() { /* Implement ... */ } 23 | public function powerOff() { /* Implement ... */ } 24 | public function bake() { /* Implement... */ } 25 | public function mix() { /* Nothing to implement ... */ } 26 | public function wash() { /* Cannot implement... */ } 27 | } 28 | 29 | class Mixer implements Appliance { 30 | public function powerOn() { /* Implement... */ } 31 | public function powerOff() { /* Implement... */ } 32 | public function bake() { /* Cannot implement... */ } 33 | public function mix() { /* Implement... */ } 34 | public function wash() { /* Cannot implement... */ } 35 | } 36 | 37 | class WashingMachine implements Appliance { 38 | public function powerOn() { /* Implement... */ } 39 | public function powerOff() { /* Implement... */ } 40 | public function bake() { /* Cannot implement... */ } 41 | public function mix() { /* Cannot implement... */ } 42 | public function wash() { /* Implement... */ } 43 | } 44 | ``` 45 | 46 | 在这里,我们有一个接口为几个设备相关的方法设置需求。然后我们有几个类实现这个接口。问题很明显,不是所有的家电都能挤进同一个接口。对于一台洗衣机来说,强迫它实现烘烤和混合方法是没有意义的。这些方法需要各自拆分到自己的接口中。这样具体的家电类就只能实现真正有意义的方法。 47 | 48 | -------------------------------------------------------------------------------- /mo-kuai-san/solid-she-ji-yuan-ze/kai-bi-yuan-ze.md: -------------------------------------------------------------------------------- 1 | # 开闭原则 2 | 3 | 开闭原则根据维基百科上的定义,一个类的扩展应该是开放的,但修改应该是封闭的。 4 | 5 | > _软件中的对象(类,模块,函数等等)应该对于扩展是开放的,但是对于修改是封闭的_ 6 | 7 | 开放的扩展部分意味着我们应该设计我们的类,以便在需要时可以添加新的功能。封闭的修改部分是指这个新功能应该适合在不修改原类的情况下使用。只有在修复bug的情况下才应该修改类,而不是为了增加新功能。 8 | 9 | 下面是一个违反开闭原则的类的例子: 10 | 11 | ```php 12 | class CsvExporter { 13 | public function export($data) { 14 | // Implementation... 15 | } 16 | } 17 | 18 | class XmlExporter { 19 | public function export($data) { 20 | // Implementation... 21 | } 22 | } 23 | 24 | class GenericExporter { 25 | public function exportToFormat($data, $format) { 26 | if ('csv' === $format) { 27 | $exporter = new CsvExporter(); 28 | } elseif ('xml' === $format) { 29 | $exporter = new XmlExporter(); 30 | } else { 31 | throw new \Exception('Unknown export format!'); 32 | } 33 | return $exporter->export($data); 34 | } 35 | } 36 | ``` 37 | 38 | 在这里,我们有两个具体的类,`CsvExporter`和`XmlExporter`,每个类都有一个职责。然后我们有一个`GenericExporter`,它的`exportToFormat`方法实际上是在一个适当的实例类型上触发导出函数。这里的问题是,我们不能在不修改`GenericExporter`类的情况下,增加一个新的类型`exporter`。换句话说,`GenericExporter`不开放扩展,封闭修改。 39 | 40 | 下面是一个重构后的实现例子,它符合OCP的要求: 41 | 42 | ```php 43 | interface ExporterFactoryInterface { 44 | public function buildForFormat($format); 45 | } 46 | 47 | interface ExporterInterface { 48 | public function export($data); 49 | } 50 | 51 | class CsvExporter implements ExporterInterface { 52 | public function export($data) { 53 | // Implementation... 54 | } 55 | } 56 | 57 | class XmlExporter implements ExporterInterface { 58 | public function export($data) { 59 | // Implementation... 60 | } 61 | } 62 | 63 | class ExporterFactory implements ExporterFactoryInterface { 64 | private $factories = array(); 65 | 66 | public function addExporterFactory($format, callable $factory) { 67 | $this->factories[$format] = $factory; 68 | } 69 | 70 | public function buildForFormat($format) { 71 | $factory = $this->factories[$format]; 72 | $exporter = $factory(); // the factory is a callable 73 | 74 | return $exporter; 75 | } 76 | } 77 | 78 | class GenericExporter { 79 | private $exporterFactory; 80 | 81 | public function __construct(ExporterFactoryInterface $exporterFactory) { 82 | $this->exporterFactory = $exporterFactory; 83 | } 84 | 85 | public function exportToFormat($data, $format) { 86 | $exporter = $this->exporterFactory->buildForFormat($format); 87 | return $exporter->export($data); 88 | } 89 | } 90 | 91 | // Client 92 | $exporterFactory = new ExporterFactory(); 93 | 94 | $exporterFactory->addExporterFactory( 95 | 'xml', 96 | function () { 97 | return new XmlExporter(); 98 | } 99 | ); 100 | 101 | $exporterFactory->addExporterFactory( 102 | 'csv', 103 | function () { 104 | return new CsvExporter(); 105 | } 106 | ); 107 | 108 | $data = array(/* ... some export data ... */); 109 | $genericExporter = new GenericExporter($exporterFactory); 110 | $csvEncodedData = $genericExporter->exportToFormat($data, 'csv'); 111 | ``` 112 | 113 | 这里我们添加了两个接口,`ExporterFactoryInterface`和`ExporterInterface`。然后我们修改`CsvExporter`和`XmlExporter`,实现该接口。添加了`ExporterFactory`,实现了`ExporterFactoryInterface`。它的主要作用是由`buildForFormat`方法定义的,该方法作为回调函数返回`exporter`。最后,重写了`GenericExporter`,通过它的构造函数接受`ExporterFactoryInterface`,它的`exportToFormat`方法现在通过使用`exporter`工厂来构建`exporter`,并调用其上的`execute`方法。 114 | 115 | 现在,客户端本身已经发挥了更强大的作用,它首先实例化`ExporterFactory`,并向其添加两个导出器,然后再将其传递给`GenericExporter`。现在向`GenericExporte`r添加一个新的导出格式,不再需要修改它,因为它的扩展是开放的,而修改是封闭的。同样,这绝不是一个通用的公式,而是一个满足OCP的可能方法的概念。 116 | 117 | -------------------------------------------------------------------------------- /mo-kuai-san/solid-she-ji-yuan-ze/li-shi-ti-huan-yuan-ze.md: -------------------------------------------------------------------------------- 1 | # 里氏替换原则 2 | 3 | 里氏替换原则说的是继承。它规定了我们应该如何设计我们的类,使客户的依赖性可以被子类所取代,而客户却看不出其中的差别,这是在维基百科上找到的定义。 4 | 5 | > _程序中的对象应该可以用它们的子类的实例来替换,而不改变程序的正确性_ 6 | 7 | 虽然子类可能会添加一些特定的功能,但它必须符合与基类相同的行为。否则就违反了里氏原则。 8 | 9 | 谈到PHP和子类,我们要超越简单的具体类,要区分:具体类、抽象类和接口。三者中的每一个都可以放在基类中,而一切扩展或实现基类的东西都可以看成是派生类。 10 | 11 | 下面是一个违反LSP的例子,派生类没有对所有方法进行实现。 12 | 13 | ```php 14 | interface User { 15 | public function getEmail(); 16 | public function getName(); 17 | public function getAge(); 18 | } 19 | 20 | class Employee implements User { 21 | public function getEmail() { 22 | // Implementation... 23 | } 24 | 25 | public function getAge() { 26 | // Implementation... 27 | } 28 | } 29 | ``` 30 | 31 | 在这里,我们看到一个 `Employee` 类没有实现接口`getName`方法。我们可以很容易地使用一个抽象类来代替接口和抽象方法类来实现`getName`方法,效果是一样的。幸运的是,在这种情况下,PHP会抛出一个错误,警告我们还没有真正完全实现接口。 32 | 33 | 下面是一个违反里氏原则的例子,不同的派生类返回不同的类型: 34 | 35 | ```php 36 | class UsersCollection implements \Iterator { 37 | // Implementation... 38 | } 39 | 40 | interface UserList { 41 | public function getUsers(); 42 | } 43 | 44 | class Emloyees implements UserList { 45 | public function getUsers() { 46 | $users = new UsersCollection(); 47 | //... 48 | return $users; 49 | } 50 | } 51 | 52 | class Directors implements UserList { 53 | public function getUsers() { 54 | $users = array(); 55 | //... 56 | return $users; 57 | } 58 | } 59 | ``` 60 | 61 | 这里我们看到一个简单的边缘案例。在两个派生类上调用`getUsers`会返回一个我们可以循环的结果。然而,PHP开发人员更倾向于在数组结构上使用`count`方法。在当前的`Employees`实例上使用它,`getUsers`的结果将无法工作。这是因为 `Employees` 类返回的是实现 `Iterator` 的 `UsersCollection`,而不是实际的数组结构。由于`UsersCollection`没有实现`Countable`,所以我们不能对它使用`count`,这就会导致潜在的bug。 62 | 63 | 我们还可以进一步发现派生类在方法参数方面表现不那么宽容的情况下的LSP违规行为。通常可以通过使用类型操作符的实例来发现这些情况,如下例所示: 64 | 65 | ```php 66 | interface LoggerProcessor { 67 | public function log(LoggerInterface $logger); 68 | } 69 | 70 | class XmlLogger implements LoggerInterface { 71 | // Implementation... 72 | } 73 | 74 | class JsonLogger implements LoggerInterface { 75 | // Implementation... 76 | } 77 | 78 | class FileLogger implements LoggerInterface { 79 | // Implementation... 80 | } 81 | 82 | class Processor implements LoggerProcessor { 83 | public function log(LoggerInterface $logger) { 84 | if ($logger instanceof XmlLogger) { 85 | throw new \Exception('This processor does not work with XmlLogger'); 86 | } else { 87 | // Implementation... 88 | } 89 | } 90 | } 91 | ``` 92 | 93 | 这里,派生类`Processor`对方法参数进行了限制,而它应该接受一切符合`LoggerInterface`的参数。通过减少允许性,它改变了基类(在本例中是`LoggerInterface`)所隐含的行为。 94 | 95 | 概述的例子只是构成违反LSP的一个片段。为了满足该原则,我们需要确保派生类不会以任何方式改变基类所施加的行为。 96 | 97 | -------------------------------------------------------------------------------- /mo-kuai-san/solid-she-ji-yuan-ze/yi-lai-fan-zhuan-yuan-ze.md: -------------------------------------------------------------------------------- 1 | # 依赖反转原则 2 | 3 | 依赖反转原则指出,实体应该依赖于抽象而不是具体实现。也就是说,一个高层次的模块不应该依赖于一个低层次的模块,而应该依赖于抽象。按照在维基百科上找到的定义: 4 | 5 | > _依赖于抽象而不是一个实例_ 6 | 7 | 这个原则很重要,因为它对我们的软件解耦起着重要作用。 8 | 9 | 下面是一个违反DIP的类的例子 10 | 11 | ```php 12 | class Mailer { 13 | // Implementation... 14 | } 15 | 16 | class NotifySubscriber { 17 | public function notify($emailTo) { 18 | $mailer = new Mailer(); 19 | $mailer->send('Thank you for...', $emailTo); 20 | } 21 | } 22 | ``` 23 | 24 | 在这里,我们可以看到`NotifySubscriber`类中的一个`notify`方法以依赖关系的方式编码给`Mailer`类。这就造成了紧耦合的代码,而这正是我们想要避免的。为了纠正这个问题,我们可以通过类构造函数,或者通过其他方法来传递依赖关系。此外,我们应该从具体的类依赖转向抽象的类依赖,如这里所示的整改后的例子所示: 25 | 26 | ```php 27 | interface MailerInterface { 28 | // Implementation... 29 | } 30 | 31 | class Mailer implements MailerInterface { 32 | // Implementation... 33 | } 34 | 35 | class NotifySubscriber { 36 | private $mailer; 37 | 38 | public function __construct(MailerInterface $mailer) { 39 | $this->mailer = $mailer; 40 | } 41 | 42 | public function notify($emailTo) { 43 | $this->mailer->send('Thank you for...', $emailTo); 44 | } 45 | } 46 | ``` 47 | 48 | 这里我们看到一个依赖关系通过构造函数被注入。注入是由一个类型提示接口和实际的具体类抽象出来的。这使得我们的代码松散耦合。DIP可以在任何时候使用,一个类需要调用另一个类的方法,或者我们应该说是向它发送消息。 49 | 50 | -------------------------------------------------------------------------------- /mo-kuai-san/symfony-gai-shu/README.md: -------------------------------------------------------------------------------- 1 | # Symfony 概述 2 | 3 | 像Symfony这样的全栈框架通过提供从用户界面到数据存储的所有必要组件,帮助简化了构建模块化应用的过程。这使得随着应用的发展,可以快速循环地交付各个零碎的应用。稍后我们将通过将我们的应用程序分割成若干个小的模块,或者Symfony术语中的捆绑包来体验这一点。 4 | 5 | 接下来,我们将安装Symfony,创建一个空白项目,并开始研究构建模块化应用所必需的单个框架功能: 6 | 7 | * 控制器 8 | * 路由 9 | * 模板 10 | * 表单 11 | * bundle 系统 12 | * 数据库和 Doctrine 13 | * 测试 14 | * 验证 15 | 16 | ## 安装Symphony 17 | 18 | 安装Symfony是非常简单的。我们可以使用以下命令在Linux或Mac OS X上安装Symfony: 19 | 20 | ```bash 21 | sudo curl -LsS https://symfony.com/installer -o /usr/local/bin/symfony 22 | sudo chmod a+x /usr/local/bin/symfony 23 | ``` 24 | 25 | 我们可以使用以下命令在Windows上安装Symfony: 26 | 27 | ```text 28 | c:\> php -r "file_put_contents('symfony', file_get_contents('https://symfony.com/installer'));" 29 | ``` 30 | 31 | 一旦命令被执行,我们可以简单地将新创建的`symfony`文件移动到我们的项目目录下,并进一步以`symfony`的形式执行,或者在Windows中以`php symfony`的形式执行。 32 | 33 | 这样就会产生如下所示的输出: 34 | 35 | ![](../../.gitbook/assets/image%20%28154%29.png) 36 | 37 | 前面的响应表明我们已经成功地设置了Symfony,现在可以开始创建新项目了。 38 | 39 | -------------------------------------------------------------------------------- /mo-kuai-san/symfony-gai-shu/bundle-xi-tong.md: -------------------------------------------------------------------------------- 1 | # bundle 系统 2 | 3 | 大多数流行的框架和平台都支持某种形式的模块、插件、扩展或 bundles。在大多数时候,两者的区别其实只是在命名上,而可扩展性和模块化的概念是一样的。在 Symfony 中,这些模块化模块被称为 bundles。 4 | 5 | bundles 是 Symfony 中的一等公民,因为它们支持其他组件的所有操作。Symfony 中的所有东西都是一个bundle,甚至是核心框架。bundles 使我们能够构建模块化的应用程序,而一个特定功能的全部代码都包含在一个目录中。 6 | 7 | 一个bundle 将所有的PHP文件,模板,样式表,JavaScript文件,测试和其他任何东西都放在一个根目录中。 8 | 9 | 当我们第一次设置测试应用程序时,它为我们创建了一个`AppBundle`,在`src`目录下。随着我们推进自动生成的CRUD,我们看到我们的 bundle 得到了各种各样的目录和文件。 10 | 11 | 要想让一个 bundle 被 Symfony 注意到,需要将它添加到`app/AppKernel.php`文件中,使用`registerBundles`方法,如图所示: 12 | 13 | ```php 14 | public function registerBundles() 15 | { 16 | $bundles = [ 17 | new Symfony\Bundle\FrameworkBundle\FrameworkBundle(), 18 | new Symfony\Bundle\SecurityBundle\SecurityBundle(), 19 | new Symfony\Bundle\TwigBundle\TwigBundle(), 20 | new Symfony\Bundle\SwiftmailerBundle\SwiftmailerBundle(), 21 | new Doctrine\Bundle\DoctrineBundle\DoctrineBundle(), 22 | //… 23 | new AppBundle\AppBundle(), 24 | ]; 25 | 26 | //… 27 | 28 | return $bundles; 29 | } 30 | ``` 31 | 32 | 创建一个新的 bundle 就像创建一个PHP文件一样简单。让我们继续创建一个`src/TestBundle/TestBundle.php`文件,内容如下: 33 | 34 | ```php 35 | namespace TestBundle; 36 | 37 | use Symfony\Component\HttpKernel\Bundle\Bundle; 38 | 39 | class TestBundle extends Bundle 40 | { 41 | … 42 | } 43 | ``` 44 | 45 | 一旦文件到位,我们需要做的就是通过`app/AppKernel.php`文件的`registerBundles`方法进行注册,如图所示: 46 | 47 | ```php 48 | class AppKernel extends Kernel { 49 | //… 50 | public function registerBundles() { 51 | $bundles = [ 52 | // … 53 | new TestBundle\TestBundle(), 54 | // … 55 | ]; 56 | return $bundles; 57 | } 58 | //… 59 | } 60 | ``` 61 | 62 | 创建一个 bundle 的更简单的方法是运行一个控制台命令,如下所示: 63 | 64 | ```bash 65 | php bin/console generate:bundle --namespace=Foggyline/TestBundle 66 | ``` 67 | 68 | 这将会触发一系列关于 bundle 的问题,最终导致 bundle 的创建,看起来像下面的截图: 69 | 70 | ![](../../.gitbook/assets/image%20%28214%29.png) 71 | 72 | 一旦完成这个过程,就会创建一个包含多个目录和文件的新 bundle,如下图所示: 73 | 74 | ![](../../.gitbook/assets/image%20%28221%29.png) 75 | 76 | Bundle 生成器很友好地创建了控制器、依赖注入扩展、路由、准备服务配置、模板,甚至测试。由于我们选择共享我们的 bundle,Symfony 选择了 XML 作为默认的配置格式。依赖扩展简单来说就是我们可以通过使用 `foggyline_test`作为 Symfony 主 `config.yml`的根元素来访问我们的 bundle 配置。实际的`foggyline_test`元素是在`DependencyInjection/Configuration.php`文件中定义的。 77 | 78 | -------------------------------------------------------------------------------- /mo-kuai-san/symfony-gai-shu/ce-shi.md: -------------------------------------------------------------------------------- 1 | # 测试 2 | 3 | 如今,测试已经成为每个现代 web 应用程序不可或缺的一部分。通常测试这个词意味着单元测试和功能测试。单元测试是关于测试我们的 PHP 类。每个 PHP 类都被认为是一个单元,因此称为单元测试。另一方面,功能测试测试我们应用程序的各个层次,通常集中于测试整个功能,比如登录或注册过程。 4 | 5 | PHP 生态系统有一个很棒的单元测试框架,叫做 PHPUnit,可以在 [https://PHPUnit.de](https://PHPUnit.de) 下载。它使我们能够编写基本的单元测试,也能够编写功能类型测试。Symfony 最棒的地方在于它内置了对 PHPUnit 的支持。 6 | 7 | 在我们开始运行 Symfony 的测试之前,我们需要确保我们已经安装了 PHPUnit,并且可以作为控制台命令使用。当执行时,`PHPUnit.xml` 或 `PHPUnit.xml.dist` 会自动尝试从当前工作目录中的 `PHPUnit.xml` 或 `PHPUnit.xml.dist` 获取和读取测试配置。默认情况下,Symfony 在其根文件夹中附带一个 `phpunit.xml.dist` 文件,因此 phpunit 命令可以选择其测试配置。 8 | 9 | 下面是默认 `phpunit.xml.dist` 文件的部分示例: 10 | 11 | ```markup 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | tests 21 | 22 | 23 | 24 | 25 | 26 | src 27 | 28 | src/*Bundle/Resources 29 | src/*/*Bundle/Resources 30 | src/*/Bundle/*Bundle/Resources 31 | 32 | 33 | 34 | 35 | ``` 36 | 37 | `Testsuites` 元素定义了目录测试,我们所有的测试都位于其中。带有其子元素的 `filter` 元素用于配置白名单以报告代码覆盖率。PHP 元素及其子元素用于配置 PHP 设置、常量和全局变量。 38 | 39 | 对我们这样的默认项目运行 `phpunit` 命令会得到如下输出: 40 | 41 | ![](../../.gitbook/assets/image%20%28211%29.png) 42 | 43 | 请注意,bundle 测试不会自动提取。所以没有执行我们的 `src/AppBundle/Tests/Controller/CustomerControllerTest.php` 文件,该文件是在我们使用自动生成的 CRUD 时自动为我们创建的。不是因为它的内容默认被注释掉了,而是因为 `bundle` 测试目录对于 `phpunit` 不可见。为了让它执行,我们需要扩展 `phpunit.xml.dist` 文件,将它添加到目录 `testsuite` 中,如下所示: 44 | 45 | ```markup 46 | 47 | 48 | tests 49 | src/AppBundle/Tests 50 | 51 | 52 | ``` 53 | 54 | 根据我们构建应用程序的方式,我们可能希望将所有 bundle 添加到 `testsuite` 列表中,即使我们计划独立发布 bundle。 55 | 56 | 关于测试还有很多要说的。我们将在后面的章节中一点一点地完成,并讨论单个 bundle 的需求。目前,了解如何触发测试以及如何向测试配置添加新位置就足够了。 57 | 58 | -------------------------------------------------------------------------------- /mo-kuai-san/symfony-gai-shu/chuang-jian-yi-ge-kong-bai-xiang-mu.md: -------------------------------------------------------------------------------- 1 | # 创建一个空白项目 2 | 3 | 现在我们已经安装好了Symfony安装程序,让我们继续创建一个新的空白项目。我们只需执行`symfony new test-app`命令,如下图所示: 4 | 5 | ![](../../.gitbook/assets/image%20%28186%29.png) 6 | 7 | 这里,我们正在创建一个新的项目,名为`test-app`。我们可以看到Symfony安装程序正在从互联网上下载最新的Symfony框架,同时输出一个简短的说明,告诉我们如何通过Symfony控制台应用程序运行内置的PHP服务器。整个过程可能需要几分钟的时间。 8 | 9 | 新建的`test-app`目录的结构如下: 10 | 11 | ![](../../.gitbook/assets/image%20%28145%29.png) 12 | 13 | 这里为我们创建了许多文件和目录。然而,我们的兴趣集中在`app`和`src`目录上。`app`目录是网站范围内的应用程序配置所在的地方,我们可以在这里找到数据库、路由、安全和其他服务的配置。同时,这里也是默认布局和模板文件的所在,如下截图所示: 14 | 15 | ![](../../.gitbook/assets/image%20%28198%29.png) 16 | 17 | 另一方面,`src`目录包含了已经模块化的基础`AppBundle`模块代码,如下截图: 18 | 19 | ![](../../.gitbook/assets/image%20%28159%29.png) 20 | 21 | 我们将在后面的学习过程中详细讨论这些文件的作用。现在,将我们的浏览器指向这个项目将使`DefaultController.php`成为实际渲染输出的文件。 22 | 23 | -------------------------------------------------------------------------------- /mo-kuai-san/symfony-gai-shu/kong-zhi-qi.md: -------------------------------------------------------------------------------- 1 | # 控制器 2 | 3 | 控制器在网络应用中扮演着重要的角色,它处于任何应用输出的最前沿。它们是端点,是在每个URL后面执行的代码。用更技术化的方式,我们可以说控制器是任何接受HTTP请求并返回HTTP响应的可调用(一个函数、一个对象上的方法或一个闭包)。响应并不像HTML那样拘泥于单一的格式,它可以是XML、JSON、CSV、图像、重定向、错误等任何形式。 4 | 5 | 让我们来看看之前创建的`src/AppBundle/Controller/CustomerController.php`文件,更准确的说是它的`newAction`方法: 6 | 7 | ```php 8 | /** 9 | * Creates a new Customer entity. 10 | * 11 | * @Route("/new", name="customer_new") 12 | * @Method({"GET", "POST"}) 13 | */ 14 | public function newAction(Request $request) 15 | { 16 | //... 17 | 18 | return $this->render('customer/new.html.twig', array( 19 | 'customer' => $customer, 20 | 'form' => $form->createView(), 21 | )); 22 | } 23 | ``` 24 | 25 | 如果我们忽略实际的数据检索部分(//...),在这个小例子中,有三件重要的事情需要注意: 26 | 27 | * @Route:这是Symfony的注解方式,指定HTTP端点,也就是我们要用来访问的URL。第一个`"/new "`参数说明了实际的端点,第二个`name="customer_new"`参数设置了这个路由的名称,然后我们可以在模板等URL生成函数中使用这个名称作为别名。值得注意的是,这是在实际定义方法的`CustomerController`类上设置的`@Route("/customer")`注解的基础上,从而使得完整的URL是类似于`http://test.app/customer/new`。 28 | * @Method:这是一个或多个HTTP方法的名称。这意味着只有当HTTP请求与之前定义的`@Route`相匹配,并且是`@Method`中定义的一个或多个HTTP方法类型时,`newAction`方法才会触发。 29 | * $this->render:这将返回`Response`对象。`$this->render`调用`Symfony/Bundle/FrameworkBundle/Controller/Controller`类的`render`函数,该函数实例化新的`Response()`,设置其内容,并返回该对象的整个实例。 30 | 31 | 现在让我们看看控制器中的`editAction`方法,部分代码块如下所示: 32 | 33 | ```php 34 | /** 35 | * Displays a form to edit an existing Customer entity. 36 | * 37 | * @Route("/{id}/edit", name="customer_edit") 38 | * @Method({"GET", "POST"}) 39 | */ 40 | public function editAction(Request $request, Customer $customer) 41 | { 42 | //... 43 | } 44 | ``` 45 | 46 | 这里,我们看到了一个接受单一ID的路由,在第一个`@Route`注解参数中标记为`{id}`。方法的主体(这里不包括在内),不包含任何获取id参数的直接引用。我们可以看到`editAction`函数接受两个参数,一个是`Request`,另一个是`Customer`。但该方法如何知道接受`Customer`对象呢?这就是Symfony的`@ParamConverter`注解发挥作用的地方。它调用转换器将请求参数转换为对象。 47 | 48 | `@ParamConverter`注解的好处是,我们可以显式或隐式地使用它。也就是说,如果我们没有添加`@ParamConverter`注解,但在方法参数中添加了类型提示,Symfony就会尝试为我们加载对象。这正是我们上面例子中的情况,因为我们没有明确地输入`@ParamConverter`注解。 49 | 50 | 从术语上来说,控制器经常被交换为路由。然而,它们并不是一回事。 51 | 52 | -------------------------------------------------------------------------------- /mo-kuai-san/symfony-gai-shu/lu-you.md: -------------------------------------------------------------------------------- 1 | # 路由 2 | 3 | 简而言之,路由就是将控制器与浏览器中输入的URL链接起来。现代网络应用需要漂亮的URL。这意味着从`/index.php?product_id=23`这样的URL转为`/catalog/product/t-shirt`这样的URL。这就是路由的作用。 4 | 5 | Symfony 有一个强大的路由机制,让我们可以做到以下几点: 6 | 7 | * 创建映射到控制器的复杂路由 8 | * 在模板内生成URL 9 | * 在控制器内生成URL 10 | * 从不同地点加载路由资源 11 | 12 | 在 Symfony 中,路由的工作方式是所有的请求都通过`app.php`。然后,Symfony 核心要求路由器检查该请求。路由器会将传入的URL与特定的路由进行匹配,并返回有关该路由的信息。这些信息,包括应该执行的控制器。最后,Symfony 内核执行控制器,控制器返回一个响应对象。 13 | 14 | 所有的应用路由都是从一个路由配置文件加载的,通常是`app/config/routing.yml`文件,如我们的测试应用所示: 15 | 16 | ```yaml 17 | app: 18 | resource: "@AppBundle/Controller/" 19 | type: annotation 20 | ``` 21 | 22 | App 只是众多可能的条目之一。它的资源值指向 `AppBundle` 控制器目录,类型设置为`annotation`,这意味着将读取类`annotations`来指定精确的路由。 23 | 24 | 我们可以用几种变化来定义一个路由。其中的一个变化如下块所示: 25 | 26 | ```php 27 | // Basic Route Configuration 28 | /** 29 | * @Route("/") 30 | */ 31 | public function homeAction() 32 | { 33 | // ... 34 | } 35 | 36 | // Routing with Placeholders 37 | /** 38 | * @Route("/catalog/product/{sku}") 39 | */ 40 | public function showAction($sku) 41 | { 42 | // ... 43 | } 44 | 45 | // >>Required<< and Optional Placeholders 46 | /** 47 | * @Route("/catalog/product/{id}") 48 | */ 49 | public function indexAction($id) 50 | { 51 | // ... 52 | } 53 | // Required and >>Optional<< Placeholders 54 | /** 55 | * @Route("/catalog/product/{id}", defaults={"id" = 1}) 56 | */ 57 | public function indexAction($id) 58 | { 59 | // ... 60 | } 61 | ``` 62 | 63 | 前面的例子展示了几种定义路由的方法。有趣的是,有必要参数和可选参数的情况。如果我们考虑一下,从最新的例子中去掉 ID,就会和前面的例子用 sku 匹配。Symfony 路由器总是会选择第一个找到的匹配路由。我们可以通过在`@Route`注解上添加正则表达式要求来解决这个问题,如下所示: 64 | 65 | ```php 66 | @Route( 67 | "/catalog/product/{id}", 68 | defaults={"id": 1}, 69 | requirements={"id": "\d+"} 70 | ) 71 | ``` 72 | 73 | 关于控制器和路由,还有更多的内容要讲,一旦我们开始构建我们的应用程序,我们就会看到。 74 | 75 | -------------------------------------------------------------------------------- /mo-kuai-san/symfony-gai-shu/mo-ban.md: -------------------------------------------------------------------------------- 1 | # 模板 2 | 3 | 前面我们说过,控制器接受请求并返回响应。然而,响应通常可以是任何内容类型。实际内容的生产是控制器委托给模板引擎的事情。然后,模板引擎有能力将响应变成HTML、JSON、XML、CSV、LaTeX或任何其他基于文本的内容类型。 4 | 5 | 在以前,程序员将PHP与HTML混合成所谓的PHP模板(`.php`和`.phtml`)。虽然现在一些平台还在使用,但这种方式被认为是不安全的,而且在很多方面都有所欠缺。其中之一就是将业务逻辑塞进模板文件中。 6 | 7 | 为了解决这些缺点,Symfony 打包了自己的模板语言`Twig`。与PHP不同的是,`Twig`的目的是严格地表达表现形式,而不是思考程序逻辑。我们无法在`Twig`中执行任何PHP代码。而`Twig`的代码不过是一个HTML,加上一些特殊的语法类型。 8 | 9 | `Twig` 定义了三种类型的特殊语法: 10 | 11 | * `{{ ... }}`: 将变量或表达式的结果输出到模板中 12 | * `{% ... %}`:这个标签控制模板的逻辑(`if`和`for`循环,以及其他) 13 | * `{# ... #}`:它相当于PHP的`/* comment */`语法。`Comments` 内容不包含在渲染的页面中 14 | 15 | 过滤器是`Twig`的另一个不错的功能。它们就像链式方法调用一个变量值一样,在输出之前修改内容,如下所示: 16 | 17 | ```markup 18 |

{{ title|upper }}

19 | 20 | {{ filter upper }} 21 |

{{ title }}

22 | {% endfilter %} 23 | 24 |

{{ title|lower|escape }}

25 | 26 | {% filter lower|escape %} 27 |

{{ title }}

28 | {% endfilter %} 29 | ``` 30 | 31 | 它还支持以下功能: 32 | 33 | ```markup 34 | {{ random(['phone', 'tablet', 'laptop']) }} 35 | ``` 36 | 37 | 前面的随机函数调用会从数组中返回一个随机值。有了所有内置的过滤器和函数列表,`Twig`还允许我们在需要的时候自己编写。 38 | 39 | 与PHP类的继承类似,`Twig`也支持模板和布局的继承。让我们快速回顾一下`app/Resources/views/customer/index.html.twig`文件,如下所示: 40 | 41 | ```markup 42 | {% extends 'base.html.twig' %} 43 | 44 | {% block body %} 45 |

Customer list

46 | … 47 | {% endblock %} 48 | ``` 49 | 50 | 这里我们看到一个客户`index.html.twig`模板,使用`extends`标签扩展另一个模板,本例中`base.html.twig`在`app/Resources/views/`目录下找到,内容如下: 51 | 52 | ```markup 53 | 54 | 55 | 56 | 57 | {% block title %}Welcome!{% endblock %} 58 | {% block stylesheets%}{% endblock %} 59 | 60 | 61 | 62 | {% block body %}{% endblock %} 63 | {% block javascripts%}{% endblock %} 64 | 65 | 66 | ``` 67 | 68 | 在这里,我们看到了几个区块标签:`1title`、`styleheets`、`body`和`javascripts`。我们可以在这里声明任意多的区块,并以任何方式命名它们。这使得扩展标签成为模板继承的关键。它告诉`Twig`首先评估基础模板,它设置了布局和定义了块,之后像`customer/index.html.twig`这样的子模板就会填充这些块的内容。 69 | 70 | 模板在两个位置: 71 | 72 | * `app/Resources/views/` 73 | * `bundle-directory/Resources/views/` 74 | 75 | 这意味着,为了 `render/extend app/Resources/views/base.html.twig`,我们将在模板文件中使用`base.html.twig`,为了`render/extend app/Resources/views/customer/index.html.twig`,我们将使用`customer/index.html.twig`路径。 76 | 77 | 当使用驻留在 bundle 中的模板时,我们必须以稍微不同的方式引用它们。在这种情况下,我们使用`bundle:directory:filename`字符串语法。以`FoggylineCatalogBundle:Product:index.html.twig`路径为例。这将是使用bundle模板文件的一个完整路径。这里`FoggylineCatalogBundle`是一个bundle名称,`Product`是该bundle `Resources/views` 目录下的一个目录名称,`index.html.twig`是`Product`目录下实际模板的名称。 78 | 79 | 每个模板文件名都有两个扩展名,首先指定格式,然后指定该模板的引擎;如`*.html.twig、*.html.php`和`*.css.twig`。 80 | 81 | 当我们开始构建我们的应用程序时,我们将进入关于这些模板的更多细节。 82 | 83 | 84 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /mo-kuai-san/symfony-gai-shu/pei-zhi-symfony.md: -------------------------------------------------------------------------------- 1 | # 配置 Symfony 2 | 3 | 为了跟上现代的需求,今天的框架和应用程序需要一个灵活的配置系统。Symfony 通过其强大的配置文件和环境概念很好地完成了这个角色。 4 | 5 | 默认的 Symfony 配置文件 `config.yml` 位于`app/config/`目录下,(部分)内容划分如下: 6 | 7 | ```yaml 8 | imports: 9 | - { resource: parameters.yml } 10 | - { resource: security.yml } 11 | - { resource: services.yml } 12 | 13 | framework: 14 | … 15 | 16 | # Twig Configuration 17 | twig: 18 | … 19 | 20 | # Doctrine Configuration 21 | doctrine: 22 | … 23 | 24 | # Swiftmailer Configuration 25 | swiftmailer: 26 | … 27 | ``` 28 | 29 | 像`framework`、`twig`、`doctrine`和`swiftmailer`这样的顶层条目定义了单个bundle的配置。 30 | 31 | 可以选择,配置文件可以是XML或PHP格式(`config.xml`或`config.php`)。虽然YAML简单易读,但XML功能更强大,而PHP功能强大但可读性较差。 32 | 33 | 我们可以使用控制台工具来转储整个配置,如图所示: 34 | 35 | ```bash 36 | php bin/console config:dump-reference FrameworkBundle 37 | ``` 38 | 39 | 前面的例子列出了core `FrameworkBundle`的配置文件。我们可以使用同样的命令来显示任何实现容器扩展的 bundle 的可能配置,这一点我们将在后面研究。 40 | 41 | Symfony 有一个很好的环境概念的实现。在`app/config`目录下,我们可以看到默认的 Symfony 项目实际上是以三种不同的环境开始的: 42 | 43 | * `config_dev.yml` 44 | * `config_prod.yml` 45 | * `config_test.yml` 46 | 47 | 每个应用程序可以在不同的环境中运行。每个环境共享相同的代码,但配置不同。开发环境可能会使用大量的日志,而prod环境可能会使用大量的缓存。 48 | 49 | 这些环境的触发方式是通过前台控制器文件,如下面的部分例子: 50 | 51 | ```php 52 | # web/app.php 53 | … 54 | $kernel = new AppKernel('prod', false); 55 | … 56 | 57 | # web/app_dev.php 58 | … 59 | $kernel = new AppKernel('dev', true); 60 | … 61 | ``` 62 | 63 | 这里缺少测试环境,因为它只在运行自动测试时使用,不能直接通过浏览器访问。 64 | 65 | `app/AppKernel.php`文件是实际加载配置的文件,无论是YAML,XML,还是PHP,如下面的代码片段所示: 66 | 67 | ```php 68 | public function registerContainerConfiguration(LoaderInterface $loader) 69 | { 70 | $loader->load($this->getRootDir().'/config/config_'.$this->getEnvironment().'.yml'); 71 | } 72 | ``` 73 | 74 | 环境遵循同样的概念,而每个环境都会导入基础配置文件,然后修改其值以适应特定环境的需要。 75 | 76 | -------------------------------------------------------------------------------- /mo-kuai-san/symfony-gai-shu/shi-yong-symfony-kong-zhi-tai.md: -------------------------------------------------------------------------------- 1 | # 使用 Symfony 控制台 2 | 3 | Symfony 框架自带了一个内置的控制台工具,我们只需在项目根目录下执行以下命令即可触发: 4 | 5 | ```bash 6 | php bin/console 7 | ``` 8 | 9 | 这样,屏幕上会显示大量可用命令列表,分为以下几组: 10 | 11 | * `assets` 12 | * `cache` 13 | * `config` 14 | * `debug` 15 | * `doctrine` 16 | * `generate` 17 | * `lint` 18 | * `orm` 19 | * `router` 20 | * `security` 21 | * `server` 22 | * `swiftmailer` 23 | * `translation` 24 | 25 | 这些赋予我们各种功能。我们今后特别关注的是`doctrine`和`generate`命令。`doctrine`命令,更具体地说,是`doctrine:generate:crud`,它基于一个现有的`Doctrine`实体生成一个CRUD。此外,`doctrine:generate:entity`命令会在现有的bundle内生成一个新的Doctrine实体。对于我们想要快速、简单地创建实体以及围绕实体的整个CRUD的情况来说,这些命令是非常方便的。同样,`generate:doctrine:entity`和`generate:doctrine:crud`也做同样的事情。 26 | 27 | 在我们继续测试这些命令之前,我们需要确保我们的数据库配置参数已经到位,这样Symfony才能看到并与我们的数据库对话。为此,我们需要在`app/config/parameters.yml`文件中设置适当的值。 28 | 29 | 在本节中,让我们继续在默认的`AppBundle`包中创建一个简单的`Customer`实体,并围绕它进行整个CRUD,假设`Customer`实体有以下属性: `firstname、lastname`和`e-mail`。我们先在项目根目录下运行`php bin/console generate:doctrine:entity`命令,结果如下: 30 | 31 | ![](../../.gitbook/assets/image%20%28170%29.png) 32 | 33 | 在这里,我们首先提供`AppBundle:Customer`作为实体名称,并确认使用注释作为配置格式。 34 | 35 | 最后,我们被要求开始向我们的实体添加字段。输入第一个名字并按下回车键,我们将通过一系列关于我们的字段类型、长度、nullable和唯一状态的简短问题,如下面的截图所示: 36 | 37 | ![](../../.gitbook/assets/image%20%28163%29.png) 38 | 39 | 现在我们应该为我们的`Customer`实体生成两个类。通过Symfony和Doctrine的帮助,这些类被放在了对象关系映射器(ORM)的上下文中,因为它们将`Customer`实体和合适的数据库表联系起来。然而,我们还没有指示Symfony为我们的实体创建表。要做到这一点,我们执行以下命令: 40 | 41 | ```bash 42 | php bin/console doctrine:schema:update --force 43 | ``` 44 | 45 | 这将产生如下截图所示的输出: 46 | 47 | ![](../../.gitbook/assets/image%20%28164%29.png) 48 | 49 | 如果我们现在看一下数据库,我们应该看到一个客户表,上面有所有适当的列,用SQL创建dsyntax创建如下: 50 | 51 | ```sql 52 | CREATE TABLE `customer` ( 53 | `id` int(11) NOT NULL AUTO_INCREMENT, 54 | `firstname` varchar(255) COLLATE utf8_unicode_ci NOT NULL, 55 | `lastname` varchar(255) COLLATE utf8_unicode_ci NOT NULL, 56 | `email` varchar(255) COLLATE utf8_unicode_ci NOT NULL, 57 | PRIMARY KEY (`id`), 58 | UNIQUE KEY `UNIQ_81398E09E7927C74` (`email`) 59 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; 60 | ``` 61 | 62 | 在这一点上,我们仍然没有一个实际的CRUD功能。我们只是有一个ORM授权的`Customer`实体类和它背后的相应数据库表。下面的命令将为我们生成实际的CRUD控制器和模板: 63 | 64 | ```bash 65 | php bin/console generate:doctrine:crud 66 | ``` 67 | 68 | 这将产生以下交互式输出: 69 | 70 | ![](../../.gitbook/assets/image%20%28150%29.png) 71 | 72 | 通过提供完全分类的实体名称`AppBundle:Customer`,生成器会进行一系列额外的输入,从生成写操作、读取的配置类型到路由的前缀,如下截图所示: 73 | 74 | ![](../../.gitbook/assets/image%20%28155%29.png) 75 | 76 | 一旦完成,我们应该能够通过简单地打开一个像 `http://test.app/customer/`(假设`test.app`是我们为我们的例子设置的主机)这样的URL来访问我们的Customer CRUD动作,如图所示: 77 | 78 | ![](../../.gitbook/assets/image%20%28206%29.png) 79 | 80 | 如果我们点击创建一个新的条目链接,我们将被重定向到`/customer/new/`URL,如下图所示: 81 | 82 | ![](../../.gitbook/assets/image%20%28167%29.png) 83 | 84 | 在这里,我们可以为我们的Customer实体输入实际值,并点击Create按钮,以便将其持久化到数据库`customer`表中。在添加了几个实体之后,现在初始的`/customer/` URL已经能够将它们全部列出,如下截图所示: 85 | 86 | ![](../../.gitbook/assets/image%20%28191%29.png) 87 | 88 | 在这里我们看到了显示和编辑操作的链接。显示操作是我们可以认为是面向客户的操作,而编辑操作是面向管理员的操作,点击编辑操作,我们会进入到`/customer/1/edit/`这个表单的URL。而这里的数字1是数据库中客户实体的ID。 89 | 90 | ![](../../.gitbook/assets/image%20%28153%29.png) 91 | 92 | 在这里,我们可以更改属性值,然后点击 "编辑 "将其持久化回数据库,也可以点击 "删除 "按钮将实体从数据库中删除。 93 | 94 | 如果我们要用一个已经存在的电子邮件创建一个新的实体,这个实体被标记为一个唯一的字段,系统会抛出一个通用的错误,比如下面这个错误: 95 | 96 | ![](../../.gitbook/assets/image%20%28199%29.png) 97 | 98 | 这只是系统默认的行为,随着我们的进一步发展,我们会研究如何让这个行为更加人性化。到现在,我们已经看到了Symfony的控制台是多么的强大。通过几个简单的命令,我们就能创建我们的实体和它的整个CRUD动作。控制台还有更多的功能,我们甚至可以创建自己的控制台命令,因为我们可以实现任何类型的逻辑。然而,就我们的需求而言,目前的实现暂时就足够了。 99 | 100 | -------------------------------------------------------------------------------- /mo-kuai-san/symfony-gai-shu/shu-ju-ku-he-doctrine.md: -------------------------------------------------------------------------------- 1 | # 数据库和 Doctrine 2 | 3 | 数据库是几乎所有网络应用的支柱。每当我们需要存储或检索数据时,我们都会借助数据库来完成。现代OOP世界的挑战是抽象数据库,使我们的 PHP 代码与数据库无关。MySQL 可能是 PHP 世界中最知名的数据库。PHP本身对 MySQL 的工作有很大的支持,无论是通过`mysqli_*`扩展还是通过 PDO。但是,这两种方法都是MySQL特有的。Doctrine 通过引入一个抽象层次来解决这个问题,使我们能够使用PHP对象来表示 MySQL中的表、行和它们的关系。 4 | 5 | Doctrine 与 Symfony 完全脱钩,所以使用它完全是可选的。然而,它的伟大之处在于,Symfony 控制台提供了基于 Doctrine ORM 的伟大的自动生成的 CRUD,正如我们在之前的例子中创建 Customer 实体时看到的那样。 6 | 7 | 我们一创建项目,Symfony 就为我们提供了一个自动生成的 `app/config/parameters.yml` 文件。在这个文件中,我们除了提供数据库访问信息外,还提供了如下示例所示的数据库访问信息: 8 | 9 | ```yaml 10 | parameters: 11 | database_host: 127.0.0.1 12 | database_port: null 13 | database_name: symfony 14 | database_user: root 15 | database_password: mysql 16 | ``` 17 | 18 | 一旦我们配置了合适的参数,我们就可以使用控制台生成功能了。 19 | 20 | 值得注意的是,这个文件中的参数只是一个约定,因为 `app/config/config.yml` 正在按照 `doctrine dbal` 进行配置,如下所示: 21 | 22 | ```php 23 | doctrine: 24 | dbal: 25 | driver: pdo_mysql 26 | host: "%database_host%" 27 | port: "%database_port%" 28 | dbname: "%database_name%" 29 | user: "%database_user%" 30 | password: "%database_password%" 31 | charset: UTF8 32 | ``` 33 | 34 | Symfony 控制台工具允许我们删除和创建一个基于这个配置的数据库,这在开发过程中很方便,如下面的代码块所示: 35 | 36 | ```bash 37 | php bin/console doctrine:database:drop --force 38 | php bin/console doctrine:database:create 39 | ``` 40 | 41 | 我们在前面看到了控制台工具如何使我们能够创建实体以及它们到数据库表的映射。这将满足我们整本书的需要。一旦我们创建了它们,我们就需要能够对它们执行 CRUD 操作。如果我们忽略自动生成的 CRUD 控制器 `src/AppBundle/Controller/CustomerController.php` 文件,我们可以按如下方式生成与 CRUD 相关的代码: 42 | 43 | ```php 44 | // Fetch all entities 45 | $customers = $em->getRepository('AppBundle:Customer')->findAll(); 46 | 47 | // Persist single entity (existing or new) 48 | $em = $this->getDoctrine()->getManager(); 49 | $em->persist($customer); 50 | $em->flush(); 51 | 52 | // Delete single entity 53 | $em = $this->getDoctrine()->getManager(); 54 | $em->remove($customer); 55 | $em->flush(); 56 | ``` 57 | 58 | 关于 Doctrine 还有很多要说的,这远远超出了本书的范围。更多信息可以在官方网页上找到\( [http://www.doctrine-project.org](http://www.doctrine-project.org) \)。 59 | 60 | -------------------------------------------------------------------------------- /mo-kuai-san/symfony-gai-shu/xiao-jie.md: -------------------------------------------------------------------------------- 1 | # 小结 2 | 3 | 在这一章中,我们提到了一些重要的功能,这些功能使得Symfony如此伟大。控制器、模板、Doctrine、ORM、表单和验证使得从数据展示和持久化都是一个完整的解决方案。我们已经看到了每个组件背后的灵活性和强大的功能。bundle 系统通过将这些组件包装成单独的迷你应用程序或模块,使其更进一步。我们现在能够完全控制传入的 HTTP 请求,操作数据存储,并将数据呈现给用户,所有这些都在一个单一的bundle 系统中完成。 4 | 5 | 接下来,在下一章中,我们将利用在前几章中获得的见解和知识,最终开始根据需求构建模块化应用程序。 6 | 7 | -------------------------------------------------------------------------------- /mo-kuai-san/symfony-gai-shu/yan-zheng.md: -------------------------------------------------------------------------------- 1 | # 验证 2 | 3 | 验证在现代应用中起着至关重要的作用。在讨论 web 应用程序时,我们可以说我们区分了两种主要的验证类型: 表单数据验证和持久数据验证。通过 web 表单从用户获取输入应该被验证,就像任何进入数据库的持久数据一样。 4 | 5 | Symfony 在这方面表现优异,它提供了一个基于 JSR 303 Bean Validation( http://beanvalidation.org/1.0/spec/) 的验证组件。如果我们回顾一下在框架根元素下的 `app/config/config.yml`,我们可以看到验证服务是默认打开的: 6 | 7 | ```yaml 8 | framework: 9 | validation:{ enable_annotations: true } 10 | ``` 11 | 12 | 我们可以通过简单的调用`$this->get('validator')`表达式从任何控制器类中访问验证服务,如下例所示: 13 | 14 | ```php 15 | $customer = new Customer(); 16 | 17 | $validator = $this->get('validator'); 18 | 19 | $errors = $validator->validate($customer); 20 | 21 | if (count($errors) > 0) { 22 | // Handle error state 23 | } 24 | 25 | // Handle valid state 26 | ``` 27 | 28 | 上面这个例子的问题是验证不会返回任何错误。这样做的原因是我们没有在类上设置任何断言。控制台自动生成的 CRUD 并没有真正定义 `Customer` 类上的任何约束。我们可以通过尝试添加一个新客户并在 e-mail 字段中键入任何文本来确认这一点,我们可以看到电子邮件不会被验证。 29 | 30 | 让我们继续编辑 `src/AppBundle/Entity/Customer.php` 文件,在 `$Email` 属性中添加 `@assert\Email` 函数,如下所示: 31 | 32 | ```php 33 | //… 34 | use Symfony\Component\Validator\Constraints as Assert; 35 | //… 36 | class Customer 37 | { 38 | //… 39 | /** 40 | * @var string 41 | * 42 | * @ORM\Column(name="email", type="string", length=255, unique=true) 43 | * @Assert\Email( 44 | * checkMX = true, 45 | * message = "Email '{{ value }}' is invalid.", 46 | * ) 47 | */ 48 | private $email; 49 | //… 50 | } 51 | ``` 52 | 53 | 关于断言约束的好处是它们接受参数就像接受函数一样。因此,我们可以根据我们的具体需要对个别约束进行微调。如果我们现在尝试跳过或添加错误的电子邮件地址,就会得到类似 **Email "john@gmail.test" is invalid** 的消息。 54 | 55 | 有许多限制可以利用,对于完整的列表,我们可以参考 [http://symfony.com/doc/current/book/validation.html](http://symfony.com/doc/current/book/validation.html) 网页。 56 | 57 | 约束可以应用于类属性或公共 getter 方法。虽然属性约束是最常见和最容易使用的,但 getter 方法约束允许我们指定更复杂的验证规则。 58 | 59 | 让我们看看 `src/AppBundle/Controller/CustomerController.php` 文件的 `newAction` 方法,如下所示: 60 | 61 | ```php 62 | $customer = new Customer(); 63 | $form = $this->createForm('AppBundle\Form\CustomerType', $customer); 64 | $form->handleRequest($request); 65 | 66 | if ($form->isSubmitted() && $form->isValid()) { 67 | // … 68 | ``` 69 | 70 | 这里我们看到一个`CustomerType`表单的实例被绑定到`Customer`实例上。实际的 GET 或 POST 请求数据通过 `handleRequest`方法传递给表单的一个实例。现在表单能够理解实体验证约束,并通过 `isValid` 方法调用做出正确的响应。这意味着我们不需要自己使用验证服务进行手动验证,表单可以为我们做这件事。 71 | 72 | 我们将继续在验证特性方面进行扩展,逐步完成单独的 bundle。 73 | 74 | -------------------------------------------------------------------------------- /mo-kuai-san/zong-jie.md: -------------------------------------------------------------------------------- 1 | # 总结 2 | 3 | 本书首先触及了设计模式和原则,作为专业编程的基础。然后,我们转而为我们的网络商店应用程序编写了一个简短的、更直观的规范。最后,我们将我们的应用程序分为核心模块和其他几个小模块,然后我们按照规范进行编码。在这个过程中,我们熟悉了一些最常用的Symfony特性。我们编写的整体应用远没有达到健壮的程度。它是一个最简单的网络商店,在功能方面还有很多需要改进的地方。然而,所应用的概念展示了在PHP中编写模块化应用是多么的简单和快捷。 4 | 5 | -------------------------------------------------------------------------------- /mo-kuai-yi/README.md: -------------------------------------------------------------------------------- 1 | # 模块一 2 | 3 | 超过80个示例,将使您的 PHP 7 网站开发技能达到新的水平! 4 | 5 | -------------------------------------------------------------------------------- /mo-kuai-yi/di-ba-zhang-chu-li-ri-qi-shi-jian-he-guo-ji-hua-fang-mian.md: -------------------------------------------------------------------------------- 1 | # 第八章、处理日期/时间和国际化方面 2 | 3 | -------------------------------------------------------------------------------- /mo-kuai-yi/di-ba-zhang-chu-li-ri-qi-shi-jian-he-guo-ji-hua-fang-mian/README.md: -------------------------------------------------------------------------------- 1 | # 第八章、处理日期/时间和国际化方面 2 | 3 | 在本章中,我们将介绍以下主题: 4 | 5 | * 在视图脚本中使用 emoji 6 | * 转换复杂字符 7 | * 从浏览器数据获取语言环境 8 | * 按地区设置数字格式 9 | * 按地区处理货币 10 | * 按地区设置日期/时间格式 11 | * 创建一个HTML国际日历生成器 12 | * 构建一个周期性事件生成器 13 | * 不使用gettext处理翻译 14 | 15 | ## 前言 16 | 17 | 在本章的开头,我们将介绍两个利用 PHP 7 中新引入的 Unicode 转义语法的事例。之后,我们将介绍如何从浏览器数据中确定网络访问者的语言环境。接下来的几个事例将包括创建一个locale类,它将允许你用一种特定的格式来表示数字、货币、日期和时间。最后,我们将介绍如何生成一个国际化的日历,处理重复发生的事件,并在不使用gettext的情况下进行翻译。 18 | 19 | -------------------------------------------------------------------------------- /mo-kuai-yi/di-ba-zhang-chu-li-ri-qi-shi-jian-he-guo-ji-hua-fang-mian/cong-liu-lan-qi-shu-ju-huo-qu-yu-yan-huan-jing.md: -------------------------------------------------------------------------------- 1 | # 从浏览器数据获取语言环境 2 | 3 | 为了改善用户在网站上的体验,以用户所在地区可以接受的格式显示信息是很重要的。本地化是一个通用术语,用来表示世界上的一个区域。I.T.社区已经做出了努力,使用一个由语言和国家代码组成的两部分指定来对地域进行编码。但是,当一个人访问你的网站时,你如何知道他们的地域?最有用的技术可能是检查HTTP语言头。 4 | 5 | ## 如何做... 6 | 7 | 1.为了封装locale功能,我们将假设一个类,`Application\I18n\Locale`。我们将让这个类扩展一个现有的类`Locale`,它是PHP `Intl`扩展的一部分。 8 | 9 | {% hint style="info" %} 10 | I18n是Internationalization的常见缩写。\(数一数字母的数量!\) 11 | {% endhint %} 12 | 13 | ```php 14 | namespace Application\I18n; 15 | use Locale as PhpLocale; 16 | class Locale extends PhpLocale 17 | { 18 | const FALLBACK_LOCALE = 'en'; 19 | // some code 20 | } 21 | ``` 22 | 23 | 2. 要了解一个传入的请求是什么样的,可以使用`phpinfo(INFO_VARIABLES)`。在测试后一定要立即关闭这个函数,因为它向潜在的攻击者提供了太多的信息。 24 | 25 | ```php 26 | 27 | ``` 28 | 29 | 3. 本地化信息存储在`$_SERVER['HTTP_ACCEPT_LANGUAGE']`中。该值将采取这种一般形式:`ll-CC,rl;q=0.n,ll-CC,rl;q=0.n`,如本表所定义。 30 | 31 | | 简称 | 定义 | 32 | | :--- | :--- | 33 | | `ll` | 代表语言的两个字符的小写代码。 | 34 | | `-` | 在地区代码`ll-CC`中把语言和国家分开。 | 35 | | `CC` | 代表国家的两个大写字母代码。 | 36 | | `,` | 分离区域代码和后备根区域代码(通常与语言代码相同)。 | 37 | | `rl` | 两个字符的小写代码,代表建议的root locale。 | 38 | | `;` | 将locale信息与quality分开。如果质量缺失,默认为q=1 \(100%\)概率,这是首选。 | 39 | | `q` | 质量。 | 40 | | `0.n` | 在0.00和1.0之间的某个值。将该值乘以100,得到该游客实际喜欢的语言的概率百分比。 | 41 | 42 | 4. 可以很容易地列出一个以上的地区。例如,网站访问者可能在他们的计算机上安装了多种语言。碰巧PHP `Locale`类有一个方法`acceptFromHttp()`,它读取`Accept-language`头字符串,并给我们提供所需的设置。 43 | 44 | ```php 45 | protected $localeCode; 46 | public function setLocaleCode($acceptLangHeader) 47 | { 48 | $this->localeCode = $this->acceptFromHttp($acceptLangHeader); 49 | } 50 | ``` 51 | 52 | 5. 然后我们可以定义相应的getter。`get AcceptLanguage()`方法从`$_SERVER['HTTP_ACCEPT_LANGUAGE']`返回值。 53 | 54 | ```php 55 | public function getAcceptLanguage() 56 | { 57 | return $_SERVER['HTTP_ACCEPT_LANGUAGE'] ?? self::FALLBACK_LOCALE; 58 | } 59 | public function getLocaleCode() 60 | { 61 | return $this->localeCode; 62 | } 63 | ``` 64 | 65 | 6. 接下来我们定义一个构造函数,允许我们 "手动 "设置locale。否则,本地语言信息将从浏览器中获取。 66 | 67 | ```php 68 | public function __construct($localeString = NULL) 69 | { 70 | if ($localeString) { 71 | $this->setLocaleCode($localeString); 72 | } else { 73 | $this->setLocaleCode($this->getAcceptLanguage()); 74 | } 75 | } 76 | ``` 77 | 78 | 7. 现在是一个重大的决定:如何处理这些信息! 这在接下来的几个事例中会有介绍。 79 | 80 | {% hint style="info" %} 81 | 即使访问者看起来接受一种或多种语言,但该访问者并不一定希望内容使用他们的浏览器所指示的语言/语言。因此,虽然您可以根据这些信息设置语言,但您也应该为他们提供一个静态的替代语言列表。 82 | {% endhint %} 83 | 84 | ## 如何运行... 85 | 86 | 在这个说明中,我们举三个例子。 87 | 88 | * 来自浏览器的信息 89 | * 预设区域 `fr-FR` 90 | * 取自`RFC 2616`的字符串:`da, en-gb;q=0.8, en;q=0.7`。 91 | 92 | 将步骤1到6的代码放入一个文件`Locale.php`中,这个文件在`Application\I18n`文件夹中。 93 | 94 | 接下来,创建一个文件,`chap_08_getting_locale_from_browser.php`,设置自动加载并使用新的类。 95 | 96 | ```php 97 | '; 113 | foreach ($locale as $code) { 114 | $locale = new Locale($code); 115 | echo ' 116 | ' . htmlspecialchars($code) . ' 117 | ' . $locale->getLocaleCode() . ' 118 | '; 119 | } 120 | echo ''; 121 | ``` 122 | 123 | 这是结果(稍微改了下输出格式)。 124 | 125 | ![](../../.gitbook/assets/image%20%28105%29.png) 126 | 127 | ## 更多... 128 | 129 | * 关于PHP `Locale`类的信息,参见[http://php.net/manual/en/class.locale.php](http://php.net/manual/en/class.locale.php)。 130 | * 有关`Accept-Language`头的更多信息,请参见RFC 2616的14.4节:[https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html](https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html)。 131 | 132 | -------------------------------------------------------------------------------- /mo-kuai-yi/di-ba-zhang-chu-li-ri-qi-shi-jian-he-guo-ji-hua-fang-mian/zai-shi-tu-jiao-ben-zhong-shi-yong-emoji.md: -------------------------------------------------------------------------------- 1 | # 在视图脚本中使用 emoji 2 | 3 | 表情一词是情感和图标的综合体。表情符号(Emoji),起源于日本,是另一套规模较大、应用广泛的图标。这些图标是小笑脸,小忍者,和在地板上打滚笑的图标,这些图标在任何有社交网络的网站上都非常流行。然而,在 PHP 7 之前,制作这些小动物是一项令人沮丧的工作。 4 | 5 | ## 如何做... 6 | 7 | 1.首先,你需要知道你想呈现的图标的Unicode。在互联网上进行快速搜索,你可以找到任何一个优秀的图表。以下是三个 “不见”、“不闻”、“不言”的猴子图标的代码。 8 | 9 | `U+1F648`, `U+1F649`和`U+1F64A` 10 | 11 | ![](../../.gitbook/assets/image%20%2894%29.png) 12 | 13 | 2.任何向浏览器输出的Unicode都必须被正确识别。这通常是通过元标签的方式来完成的。你应该将字符集设置为UTF-8。下面是一个例子。 14 | 15 | ```markup 16 | 17 | PHP 7 Cookbook 18 | 19 | 20 | ``` 21 | 22 | 3. 传统的方法是简单地使用HTML来显示图标。因此,你可以这样做。 23 | 24 | ```markup 25 | 26 | 27 | 28 | 29 | 30 | 31 |
🙈🙉🙊
32 | ``` 33 | 34 | 4. 从 PHP 7 开始,现在可以使用这种语法来构造完整的 Unicode 字符。"`\u{xxx}`"。下面是一个例子,它的三个图标与上面的相同。 35 | 36 | ```php 37 | 38 | 39 | 40 | 41 | 42 | 43 |
44 | ``` 45 | 46 | {% hint style="info" %} 47 | 你的操作系统和浏览器必须同时支持Unicode,并且必须有正确的字体集。例如,在Ubuntu Linux中,你需要安装`ttf-ancient-fonts`软件包才能在浏览器中看到表情符号。 48 | {% endhint %} 49 | 50 | ## 如何运行... 51 | 52 | 在 PHP 7 中,引入了一种新的语法,可以渲染任何 Unicode 字符。与其他语言不同的是,新的 PHP 语法允许使用可变数量的十六进制数字。基本格式是这样的。 53 | 54 | ```php 55 | \u{xxxx} 56 | ``` 57 | 58 | 整个结构必须使用双引号\(或使用heredoc\)。 xxxx可以是任意的十六进制数字组合,2、4、6及以上。 59 | 60 | 创建一个名为`chap_08_emoji_using_html.php`的文件。确保包含元标签,向浏览器发出UTF-8字符编码的信号。 61 | 62 | ```markup 63 | 64 | 65 | 66 | PHP 7 Cookbook 67 | 68 | 69 | ``` 70 | 71 | 接下来,建立一个基本的HTML表格,并显示一排表情。 72 | 73 | ```markup 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 |
🙈🙉🙊
82 | 83 | 84 | ``` 85 | 86 | 现在,使用PHP添加一行来发出表情。 87 | 88 | ```php 89 | 90 | 91 | 92 | 93 | 94 | ``` 95 | 96 | 这是从Firefox看到的输出。 97 | 98 | ![](../../.gitbook/assets/image%20%28108%29.png) 99 | 100 | ## 更多... 101 | 102 | 表情代码列表,见[http://unicode.org/emoji/charts/full-emoji-list.html](http://unicode.org/emoji/charts/full-emoji-list.html)。 103 | 104 | -------------------------------------------------------------------------------- /mo-kuai-yi/di-ba-zhang-chu-li-ri-qi-shi-jian-he-guo-ji-hua-fang-mian/zhuan-huan-fu-za-zi-fu.md: -------------------------------------------------------------------------------- 1 | # 转换复杂字符 2 | 3 | 访问整个Unicode字符集的能力为渲染复杂的字符提供了许多新的可能性,特别是拉丁字母以外的字符。 4 | 5 | ## 如何做... 6 | 7 | 1.有些语言的读法是从右到左,而不是从左到右。例如希伯来语和阿拉伯语。在这个例子中,我们向您展示如何使用`U+202E` Unicode字符来呈现从右到左覆盖的反向文本。下面这行代码打印了`txet desreveR`。 8 | 9 | ```php 10 | echo "\u{202E}Reversed text"; 11 | echo "\u{202D}"; // returns output to left-to-right 12 | ``` 13 | 14 | {% hint style="info" %} 15 | 完成后别忘了调用从左到右的覆盖字符`U+202D`! 16 | {% endhint %} 17 | 18 | 2. 另一个考虑因素是使用合成字符。其中一个例子是`ñ`(字母`n`,上面有一个tilde `~`)。这在诸如`mañana`(西班牙语中的早晨或明天,取决于上下文)这样的单词中使用。还有一个可用的组成字符,由Unicode代码`U+00F1`表示。下面是其使用的一个例子,与`mañana`相呼应。 19 | 20 | ```php 21 | echo "ma\u{00F1}ana"; // shows mañana 22 | ``` 23 | 24 | 3. 然而,这可能会潜在地影响搜索的可能性。想象一下,你的客户没有一个带有这个组成字符的键盘。如果他们开始输入`man`试图搜索`mañana`,他们将不成功。 25 | 26 | 4. 使用完整的Unicode集提供了其他的可能性。你可以不使用组成的字符,而是使用原始字母`n`与Unicode组合码的组合,将浮动的tilde置于字母之上。在这个`echo`命令中,输出的结果和之前一样。只是组成单词的方式不同。 27 | 28 | ```php 29 | echo "man\u{0303}ana"; // also shows mañana 30 | ``` 31 | 32 | 5. 对于重音也可以有类似的应用。考虑一下法语单词`élève`(学生)。您可以使用合成字符来呈现它,或者使用组合代码将重音浮在字母上方。考虑以下两个例子。这两个例子产生了相同的输出,但呈现方式不同。 33 | 34 | ```php 35 | echo "\u{00E9}l\u{00E8}ve"; 36 | echo "e\u{0301}le\u{0300}ve"; 37 | ``` 38 | 39 | ## 如何运行... 40 | 41 | 创建一个名为`chap_08_control_and_combining_unicode.php`的文件。确保包含元标签,向浏览器发出UTF-8字符编码的信号。 42 | 43 | ```markup 44 | 45 | 46 | 47 | PHP 7 Cookbook 48 | 49 | 50 | ``` 51 | 52 | 接下来,设置基本的PHP和HTML来显示前面讨论的例子。 53 | 54 | ```php 55 | 56 |
57 |       
67 |     
68 | 69 | 70 | ``` 71 | 72 | 下面是浏览器的输出。 73 | 74 | ![](../../.gitbook/assets/image%20%28104%29.png) 75 | 76 | -------------------------------------------------------------------------------- /mo-kuai-yi/di-er-zhang-shi-yong-php-7-gao-xing-neng-te-xing.md: -------------------------------------------------------------------------------- 1 | # 第二章: 使用 PHP 7 高性能特性 2 | 3 | 在这一章中,我们将讨论和理解 PHP 5和 PHP 7之间的语法差异,特别是以下几点: 4 | 5 | * 了解抽象语法树 6 | * 了解解析的差异 7 | * 了解 `foreach()` 处理方式的差异 8 | * 使用PHP 7增强功能来提高性能 9 | * 遍历海量文件 10 | * 将电子表格上传到数据库 11 | * 递归目录迭代器 12 | 13 | ## 引言 14 | 15 | 在本章中,我们将直接进入PHP 7,介绍利用新的高性能特性的示例。 但是,首先,我们将提供一系列较小的示例,这些示例用来说明PHP 7在处理参数解析,语法,`foreach()` 循环和其他增强功能方面的差异。 在深入本章之前,让我们讨论PHP 5和PHP 7之间的一些基本区别。 16 | 17 | PHP 7引入了一个称为**抽象语法树**\(**AST**\)的新层,该层有效地将解析过程与伪编译过程解耦。 尽管新层对性能几乎没有影响,但是却为语言提供了新的语法统一性,这在以前是不可能的。 18 | 19 | AST 的另一个好处是取消引用的过程。 简单地说,取消引用是指能够立即从对象获取属性或运行对象的方法,立即访问数组元素并立即执行回调的能力。 在PHP 5中,这种支持是不一致和不完整的。 例如,要执行回调,通常首先需要将回调或匿名函数分配给变量,然后再执行它。 在PHP 7中,您可以立即执行它。 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /mo-kuai-yi/di-er-zhang-shi-yong-php-7-gao-xing-neng-te-xing/README.md: -------------------------------------------------------------------------------- 1 | # 第二章、使用 PHP 7 高性能特性 2 | 3 | 在这一章中,我们将讨论和理解 PHP 5和 PHP 7之间的语法差异,特别是以下几点: 4 | 5 | * 了解抽象语法树 6 | * 理解句法分析中的差异 7 | * 理解 `foreach()` 处理方式的差异 8 | * 使用 PHP 7 增强功能来提高性能 9 | * 遍历海量文件 10 | * 将电子表格上传到数据库 11 | * 递归目录迭代器 12 | 13 | ## 引言 14 | 15 | 在本章中,我们将直接进入PHP 7,介绍利用新的高性能特性的示例。 但是,首先,我们将提供一系列较小的示例,这些示例用来说明PHP 7在处理参数解析,语法,`foreach()` 循环和其他增强功能方面的差异。 在深入本章之前,让我们讨论PHP 5和PHP 7之间的一些基本区别。 16 | 17 | PHP 7引入了一个称为**抽象语法树**\(**AST**\)的新层,该层有效地将解析过程与伪编译过程解耦。 尽管新层对性能几乎没有影响,但是却为语言提供了新的语法统一性,这在以前是不可能的。 18 | 19 | AST 的另一个好处是取消引用的过程。 简单地说,取消引用是指能够立即从对象获取属性或运行对象的方法,立即访问数组元素并立即执行回调的能力。 在PHP 5中,这种支持是不一致和不完整的。 例如,要执行回调,通常首先需要将回调或匿名函数分配给变量,然后再执行它。 在PHP 7中,您可以立即执行它。 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /mo-kuai-yi/di-er-zhang-shi-yong-php-7-gao-xing-neng-te-xing/bian-li-hai-liang-wen-jian.md: -------------------------------------------------------------------------------- 1 | # 遍历海量文件 2 | 3 | 像 `file_get_contents()` 和 `file()` 这样的函数使用起来非常方便快捷,但是由于内存的限制,当处理大量的文件时,它们很快就会产生问题。`php.ini` 内存限制的默认设置是128兆字节。因此,任何大于这个值的文件都不会被加载。 4 | 5 | 在解析海量文件时,另一个需要考虑的问题是函数或类方法产出的速度有多快? 例如,在生成用户输出时,尽管乍一看似乎可以将输出累加到数组中。 然后,您将立即输出所有内容以提高效率。 不幸的是,这可能会对用户体验产生不利影响。 创建一个**生成器**,并使用 `yield` 关键字产生即时结果可能会更好。 6 | 7 | ## 如何做... 8 | 9 | 如前文所述, `file*` 函数(即 `file_get_contents()` ),不适合大文件。原因很简单,这些函数,在某一点上,文件的全部内容都会写入到内存中。因此,本示例的重点是 `f*` 函数(即 `fopen()` )。 10 | 11 | 然而,稍有变化的是,我们将不直接使用 `f*` 函数,而是使用**SPL**(**标准PHP库**)中包含的 `SplFileObject` 类。 12 | 13 | 1.首先,我们定义一个 `Application\Iterator\LargeFile` 类,并赋予相应的属性和常量: 14 | 15 | ```php 16 | namespace Application\Iterator; 17 | 18 | use Exception; 19 | use InvalidArgumentException; 20 | use SplFileObject; 21 | use NoRewindIterator; 22 | 23 | class LargeFile 24 | { 25 | const ERROR_UNABLE = 'ERROR: Unable to open file'; 26 | const ERROR_TYPE = 'ERROR: Type must be "ByLength", "ByLine" or "Csv"'; 27 | protected $file; 28 | protected $allowedTypes = ['ByLine', 'ByLength', 'Csv']; 29 | ``` 30 | 31 | 2.然后我们定义了一个 `__construct()` 方法,它接受一个文件名作为参数,并用一个 `SplFileObject` 实例填充 `$file` 属性。如果文件不存在,这也是一个抛出异常的好地方: 32 | 33 | ```php 34 | public function __construct($filename, $mode = 'r') 35 | { 36 | if (!file_exists($filename)) { 37 | $message = __METHOD__ . ' : ' . self::ERROR_UNABLE . PHP_EOL; 38 | $message .= strip_tags($filename) . PHP_EOL; 39 | throw new Exception($message); 40 | } 41 | $this->file = new SplFileObject($filename, $mode); 42 | } 43 | ``` 44 | 45 | 3.接下来我们定义一个 `fileIteratorByLine()` 方法,该方法使用 `fgets()` 一次读取文件的一行。另创建一个 `fileIteratorByLength()` 方法,它可以做同样的事情,但使用 `fread()` 来代替。使用 `fgets()` 的方法适用于包含换行的文本文件。如果解析一个大的二进制文件,可以使用另一个方法: 46 | 47 | ```php 48 | protected function fileIteratorByLine() 49 | { 50 | $count = 0; 51 | while (!$this->file->eof()) { 52 | yield $this->file->fgets(); 53 | $count++; 54 | } 55 | return $count; 56 | } 57 | 58 | protected function fileIteratorByLength($numBytes = 1024) 59 | { 60 | $count = 0; 61 | while (!$this->file->eof()) { 62 | yield $this->file->fread($numBytes); 63 | $count++; 64 | } 65 | return $count; 66 | } 67 | ``` 68 | 69 | 4.最后,我们定义一个 `getIterator()` 方法,返回一个 `NoRewindIterator()` 实例。这个方法接受 `ByLine` 或 `ByLength` 作为参数,它们指的是上一步定义的两个方法。在调用 `ByLength` 的情况下,这个方法还需要接受 `$numBytes`。我们需要 `NoRewindIterator()` 实例的原因是,在这个例子中,我们只从一个方向读取文件: 70 | 71 | ```php 72 | public function getIterator($type = 'ByLine', $numBytes = NULL) 73 | { 74 | if(!in_array($type, $this->allowedTypes)) { 75 | $message = __METHOD__ . ' : ' . self::ERROR_TYPE . PHP_EOL; 76 | throw new InvalidArgumentException($message); 77 | } 78 | $iterator = 'fileIterator' . $type; 79 | return new NoRewindIterator($this->$iterator($numBytes)); 80 | } 81 | ``` 82 | 83 | ## 如何运行... 84 | 85 | 首先,我们利用第一章《建立基础》中定义的自动加载类,在调用程序中获取 `Application\Iterator\LargeFile` 的实例, `chap_02_iterating_through_a_massive_file.php` : 86 | 87 | ```php 88 | define('MASSIVE_FILE', '/../data/files/war_and_peace.txt'); 89 | require __DIR__ . '/../Application/Autoload/Loader.php'; 90 | Application\Autoload\Loader::init(__DIR__ . '/..'); 91 | ``` 92 | 93 | 接下来,在 `try {...} catch () {...}` 块里面,我们得到一个 `ByLine` 迭代器的实例: 94 | 95 | ```php 96 | try { 97 | $largeFile = new Application\Iterator\LargeFile(__DIR__ . MASSIVE_FILE); 98 | $iterator = $largeFile->getIterator('ByLine'); 99 | ``` 100 | 101 | 然后,我们提供一个有用的示例,在这种情况下,定义每行平均单词数: 102 | 103 | ```php 104 | $words = 0; 105 | foreach ($iterator as $line) { 106 | echo $line; 107 | $words += str_word_count($line); 108 | } 109 | echo str_repeat('-', 52) . PHP_EOL; 110 | printf("%-40s : %8d\n", 'Total Words', $words); 111 | printf("%-40s : %8d\n", 'Average Words Per Line', 112 | ($words / $iterator->getReturn())); 113 | echo str_repeat('-', 52) . PHP_EOL; 114 | ``` 115 | 116 | 然后,我们结束catch块: 117 | 118 | ```php 119 | } catch (Throwable $e) { 120 | echo $e->getMessage(); 121 | } 122 | ``` 123 | 124 | 预期的输出(太大了,这里就不显示了!)在本示例中我们采用了古腾堡版的《战争与和平》其中有566,095个字。另外,我们发现每行的平均字数是8个。 125 | 126 | -------------------------------------------------------------------------------- /mo-kuai-yi/di-er-zhang-shi-yong-php-7-gao-xing-neng-te-xing/jiang-dian-zi-biao-ge-shang-chuan-dao-shu-ju-ku.md: -------------------------------------------------------------------------------- 1 | # 将电子表格上传到数据库 2 | 3 | 尽管 PHP 没有任何直接读取特定电子表格格式的能力(如 XLSX、ODS 等),但它有读取(CSV 逗号分隔值)文件的能力,因此,为了处理客户的电子表格,需要要求他们提供 CSV 格式的文件,或者需要自己进行转换。 4 | 5 | ## 准备... 6 | 7 | 当要把电子表格(即CSV文件)上传到数据库中时,有三个主要的考虑因素: 8 | 9 | * 迭代一个(潜在的)庞大的文件 10 | * 将每个电子表格的行提取到一个PHP数组中 11 | * 在数据库中插入PHP数组 12 | 13 | 大规模的文件迭代使用前面的示例来处理,我们使用 `fgetcsv()` 函数将CSV行转换为PHP数组。最后,我们使用\(**PDO PHP Data Objects**\)类建立数据库连接并进行插入。 14 | 15 | ## 如何做... 16 | 17 | 1.首先,我们定义一个 `Application\Database\Connection` 类,该类根据提供给构造函数的一组参数创建一个 PDO 实例。 18 | 19 | ```php 20 | pdo = new PDO($dsn, 42 | $config['user'], 43 | $config['password'], 44 | [PDO::ATTR_ERRMODE => $config['errmode']]); 45 | } catch (PDOException $e) { 46 | error_log($e->getMessage()); 47 | } 48 | } 49 | 50 | } 51 | ``` 52 | 53 | 2.然后,我们加入一个 `Application\Iterator\LargeFile` 的实例。我们在这个类中添加了一个新的方法,这个方法被设计用来迭代 CSV 文件: 54 | 55 | ```php 56 | protected function fileIteratorCsv() 57 | { 58 | $count = 0; 59 | while (!$this->file->eof()) { 60 | yield $this->file->fgetcsv(); 61 | $count++; 62 | } 63 | return $count; 64 | } 65 | ``` 66 | 67 | 3.我们还需要将 Csv 添加到允许的迭代器方法列表中: 68 | 69 | ```php 70 | const ERROR_UNABLE = 'ERROR: Unable to open file'; 71 | const ERROR_TYPE = 'ERROR: Type must be "ByLength", "ByLine" or "Csv"'; 72 | 73 | protected $file; 74 | protected $allowedTypes = ['ByLine', 'ByLength', 'Csv']; 75 | ``` 76 | 77 | ## 如何运行... 78 | 79 | 首先我们定义一个配置文件, `/path/to/source/config/db.config.php` ,其中包含数据库连接参数: 80 | 81 | ```php 82 | 'mysql', 85 | 'host' => 'localhost', 86 | 'dbname' => 'php7cookbook', 87 | 'user' => 'cook', 88 | 'password' => 'book', 89 | 'errmode' => PDO::ERRMODE_EXCEPTION, 90 | ]; 91 | ``` 92 | 93 | 接下来,我们利用第一章 《建立基础》 中定义的自动加载类,获得 `Application\Database\DatabaseConnection` 和 `Application\Iterator\LargeFile` 的实例,定义一个调用程序,`chap_02_uploading_csv_to_database.php` 。 94 | 95 | ```php 96 | define('DB_CONFIG_FILE', '/../data/config/db.config.php'); 97 | define('CSV_FILE', '/../data/files/prospects.csv'); 98 | require __DIR__ . '/../../Application/Autoload/Loader.php'; 99 | Application\Autoload\Loader::init(__DIR__ . '/..'); 100 | ``` 101 | 102 | 之后,我们设置了一个 `try {...} catch () {...}` 块,它可以捕获 `Throwable` 。这样我们就可以同时捕获异常和错误: 103 | 104 | ```php 105 | try { 106 | // ... 107 | } catch (Throwable $e) { 108 | echo $e->getMessage(); 109 | } 110 | ``` 111 | 112 | 在 `try {...} catch () {...}` 块里面,我们得到一个连接和大文件迭代器类的实例: 113 | 114 | ```php 115 | $connection = new Application\Database\Connection( 116 | include __DIR__ . DB_CONFIG_FILE); 117 | $iterator = (new Application\Iterator\LargeFile(__DIR__ . CSV_FILE)) 118 | ->getIterator('Csv'); 119 | ``` 120 | 121 | 然后我们利用PDO的 prepare/execute 功能。准备语句 SQL 中的 `?` 表示参数标记,参数在SQL执行时会被替换: 122 | 123 | ```php 124 | $sql = 'INSERT INTO `prospects` ' 125 | . '(`id`,`first_name`,`last_name`,`address`,`city`,`state_province`,' 126 | . '`postal_code`,`phone`,`country`,`email`,`status`,`budget`,`last_updated`) ' 127 | . ' VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)'; 128 | $statement = $connection->pdo->prepare($sql); 129 | ``` 130 | 131 | 然后我们使用 `foreach()` 来循环执行文件迭代器。每一条 `yield` 语句都会产生一个代表数据库中一行值的数组。然后,我们可以使用这些值与 `PDOStatement::execute()` 来执行准备好的语句,将该行的值插入到数据库中。 132 | 133 | ```php 134 | foreach ($iterator as $row) { 135 | echo implode(',', $row) . PHP_EOL; 136 | $statement->execute($row); 137 | } 138 | ``` 139 | 140 | 然后可以检查数据库,以验证数据是否已成功插入。 141 | 142 | -------------------------------------------------------------------------------- /mo-kuai-yi/di-er-zhang-shi-yong-php-7-gao-xing-neng-te-xing/li-jie-ju-fa-fen-xi-zhong-de-cha-yi.md: -------------------------------------------------------------------------------- 1 | # 理解句法分析中的差异 2 | 3 | 在 PHP 5中,赋值操作右侧的表达式是从右向左解析的。在 PHP 7中,解析始终是从左到右的。 4 | 5 | ## 如何做... 6 | 7 | 1.变量-变量是间接引用值的一种方式。 在下面的示例中,第一个 `$$foo` 被解释为 `${$bar}` 。 因此,最终的返回值是 `$bar` 的值,而不是 `$foo` 的直接值(可能是 `bar`): 8 | 9 | ```php 10 | $foo = 'bar'; 11 | $bar = 'baz'; 12 | echo $$foo; // 返回 'baz'; 13 | ``` 14 | 15 | 2.在下一个示例中,我们有一个变量-变量 `$$foo` ,该变量引用带有 `bar`键和 `baz` 子键的多维数组: 16 | 17 | ```php 18 | $foo = 'bar'; 19 | $bar = ['bar' => ['baz' => 'bat']]; 20 | // 返回 'bat' 21 | echo $$foo['bar']['baz']; 22 | ``` 23 | 24 | 3.在PHP 5中,解析是从右到左进行的,这意味着PHP引擎将寻找带有 `bar` 键和 `baz` 子键的 `$foo` 数组。 然后将解释该元素的返回值以获得最终值 `${$foo['bar']['baz']}`。 25 | 26 | 4.但是,在PHP 7中,解析始终是从左到右,这意味着 `$foo` 首先被解释 `($$foo)['bar']['baz']` 。 27 | 28 | 5.在下一个示例中,您可以看到与PHP 7相比,PHP 5中对 `$foo->$bar['bada']` 的解释完全不同。在下面的示例中,PHP 5将首先解释 `$bar['bada']` ,并针对 `$foo` 对象实例引用此返回值。 另一方面,在PHP 7中,解析始终是从左到右,这意味着 `$foo->$bar` 首先被解释,并且期望包含 `bada` 元素的数组。 您还将注意到,该示例使用了PHP 7匿名类功能: 29 | 30 | ```php 31 | // PHP 5: $foo->{$bar['bada']} 32 | // PHP 7: ($foo->$bar)['bada'] 33 | $bar = 'baz'; 34 | // $foo = new class 35 | { 36 | public $baz = ['bada' => 'boom']; 37 | }; 38 | // returns 'boom' 39 | echo $foo->$bar['bada']; 40 | ``` 41 | 42 | 6.最后一个示例与上面的示例相同,不同之处在于返回值是个回调,然后立即执行: 43 | 44 | ```php 45 | // PHP 5: $foo->{$bar['bada']}() 46 | // PHP 7: ($foo->$bar)['bada']() 47 | $bar = 'baz'; 48 | // 注意: 这个例子使用了新的 PHP 7匿名类特性 49 | $foo = new class 50 | { 51 | public function __construct() 52 | { 53 | $this->baz = ['bada' => function () { return 'boom'; }]; 54 | } 55 | }; 56 | // 返回 'boom' 57 | echo $foo->$bar['bada'](); 58 | ``` 59 | 60 | ## 如何运行... 61 | 62 | 将1和2中所示的代码示例放在一个单独的PHP文件中,您可以命名为 `chap_02_understanding_diffs_in_parsing.php` 。 首先使用PHP 5执行该脚本,您将注意到一系列错误,如下所示: 63 | 64 | ![](../../.gitbook/assets/image%20%2833%29.png) 65 | 66 | 错误的原因是PHP 5解析不一致,并且就请求的变量-变量的状态得出了错误的结论(如前所述)。 现在,您可以继续添加其余示例,如步骤5和6所示。如果您随后在PHP 7中运行此脚本,则将显示所描述的结果,如下所示: 67 | 68 | ![](../../.gitbook/assets/image%20%2828%29.png) 69 | 70 | ## 参考 71 | 72 | 有关解析的更多信息,请参考 RFC,它提供了统一变量语法,并且可以在 [https://wiki.php.net/RFC/uniform\_variable\_syntax](https://wiki.php.net/RFC/uniform_variable_syntax) 查看。 73 | 74 | -------------------------------------------------------------------------------- /mo-kuai-yi/di-er-zhang-shi-yong-php-7-gao-xing-neng-te-xing/shi-yong-php-7-zeng-qiang-gong-neng-ti-gao-xing-neng.md: -------------------------------------------------------------------------------- 1 | # 使用 PHP 7 增强功能提高性能 2 | 3 | 一个趋势是,开发者开始使用匿名函数。当处理匿名函数时,一个典型的问题是,如何将它们写成任何对象都可以绑定到 `$this` 的形式,并且函数仍然可以工作。在 PHP 5 代码中使用的方法是使用 `bindTo()` 。在 PHP 7 中,增加了一个新的方法 `call()` ,它提供了类似的功能,但性能有很大的提升。 4 | 5 | ## 如何做... 6 | 7 | 为了利用 `call()` ,在一个冗长的循环中执行一个匿名函数。在这个例子中,我们将演示一个匿名函数,它可以扫描一个日志文件,根据出现的频率识别 IP 地址: 8 | 9 | 1.首先,我们定义一个 `Application\Web\Access` 类。 在构造函数中,我们接受文件名作为参数。日志文件通过 `SplFileObject` 打开,并分配给 `$this->log` : 10 | 11 | ```php 12 | Namespace Application\Web; 13 | 14 | use Exception; 15 | use SplFileObject; 16 | class Access 17 | { 18 | const ERROR_UNABLE = 'ERROR: unable to open file'; 19 | protected $log; 20 | public $frequency = array(); 21 | public function __construct($filename) 22 | { 23 | if (!file_exists($filename)) { 24 | $message = __METHOD__ . ' : ' . self::ERROR_UNABLE . PHP_EOL; 25 | $message .= strip_tags($filename) . PHP_EOL; 26 | throw new Exception($message); 27 | } 28 | $this->log = new SplFileObject($filename, 'r'); 29 | } 30 | ``` 31 | 32 | 2.接下来,我们定义一个生成器,逐行遍历文件: 33 | 34 | ```php 35 | public function fileIteratorByLine() 36 | { 37 | $count = 0; 38 | while (!$this->log->eof()) { 39 | yield $this->log->fgets(); 40 | $count++; 41 | } 42 | return $count; 43 | } 44 | ``` 45 | 46 | 3. 最后,我们定义了一个寻找并提取一个IP地址作为子匹配的方法: 47 | 48 | ```php 49 | public function getIp($line) 50 | { 51 | preg_match('/(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/', $line, $match); 52 | return $match[1] ?? ''; 53 | } 54 | } 55 | ``` 56 | 57 | ## 如何运行... 58 | 59 | 首先,我们定义一个调用程序 `chap_02_performance_using_php7_enchancement_call.php` ,该程序利用第一章《建立基础》中定义的自动加载类来获取 `Application\Web\Access` 的实例: 60 | 61 | ```php 62 | define('LOG_FILES', '/var/log/apache2/*access*.log'); 63 | require __DIR__ . '/../Application/Autoload/Loader.php'; 64 | Application\Autoload\Loader::init(__DIR__ . '/..'); 65 | ``` 66 | 67 | 接下来我们定义匿名函数,处理日志文件中的一行。如果检测到一个IP地址,它就会成为 `$frequency` 数组中的一个键,并且这个键的当前值会递增: 68 | 69 | ```php 70 | // 定义方法 71 | $freq = function ($line) { 72 | $ip = $this->getIp($line); 73 | if ($ip) { 74 | echo '.'; 75 | $this->frequency[$ip] = 76 | (isset($this->frequency[$ip])) ? $this->frequency[$ip] + 1 : 1; 77 | } 78 | }; 79 | ``` 80 | 81 | 然后,我们在每个找到的日志文件中循环迭代行,处理IP地址: 82 | 83 | ```php 84 | foreach (glob(LOG_FILES) as $filename) { 85 | echo PHP_EOL . $filename . PHP_EOL; 86 | // 存取类 87 | $access = new Application\Web\Access($filename); 88 | foreach ($access->fileIteratorByLine() as $line) { 89 | $freq->call($access, $line); 90 | } 91 | } 92 | ``` 93 | 94 | > **小贴士** 95 | > 96 | > 实际上在 PHP 5 中也可以做同样的事情,但是需要两行代码。 97 | > 98 | > ```php 99 | > $func = $freq->bindTo($access); 100 | > $func($line); 101 | > ``` 102 | > 103 | > 性能比在 PHP 7 中使用 `call()` 慢20%到50%。 104 | 105 | 最后,我们对数组进行反向排序,但保留键。然后通过简单的 `foreach()` 循环输出: 106 | 107 | ```php 108 | arsort($access->frequency); 109 | foreach ($access->frequency as $key => $value) { 110 | printf('%16s : %6d' . PHP_EOL, $key, $value); 111 | } 112 | ``` 113 | 114 | 他的输出会根据你处理的 `access.log` 而有所不同。下面是一个例子: 115 | 116 | ![](../../.gitbook/assets/image%20%2824%29.png) 117 | 118 | ## 更多... 119 | 120 | 许多 PHP 7 的性能改进与新特性和功能无关。相反,它们采取的是内部改进的形式,在开始运行程序之前是看不见的。以下是属于这一类的改进的简短列表: 121 | 122 | | 功能 | 更多信息 | 注释 | 123 | | :--- | :--- | :--- | 124 | | 快速参数解析 | [https://wiki.php.net/rfc/fast\_zpp](https://wiki.php.net/rfc/fast_zpp) | 在 PHP 5 中,每次调用函数时都要对提供给函数的参数进行解析。参数以字符串的形式传入,并以类似于 `scanf()` 函数的方式进行解析。在 PHP 7 中,这个过程得到了优化,变得更加高效,从而使性能得到了显著的提高。这种改进很难衡量,但似乎在6%左右。 | 125 | | PHP NG | [https://wiki.php.net/rfc/phpng](https://wiki.php.net/rfc/phpng) | PHP NG(下一代)计划代表了PHP语言的大部分重写。它保留了现有的功能,但包含了所有可以想象到的节省时间和提高效率的措施。数据结构被压缩,内存被更有效地使用。仅仅是一个影响数组处理的变化,就使性能得到了显著的提高,同时大大减少了内存的使用。 | 126 | | 删除无效的扩展 | [https://wiki.php.net/rfc/removal\_of\_dead\_sapis\_and\_exts](https://wiki.php.net/rfc/removal_of_dead_sapis_and_exts) | 大约有二十多个扩展属于这些类别中的一种:废弃的、不再维护的、未维护的依赖关系、或未移植到 PHP 7。经过核心开发人员的投票,决定删除 2/3 或 "短名单 "上的扩展。这样做的结果是减少了开销,加快了PHP语言未来的整体开发速度。 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | -------------------------------------------------------------------------------- /mo-kuai-yi/di-jiu-zhang-kai-fa-zhong-jian-jian.md: -------------------------------------------------------------------------------- 1 | # 第九章、开发中间件 2 | 3 | -------------------------------------------------------------------------------- /mo-kuai-yi/di-jiu-zhang-kai-fa-zhong-jian-jian/README.md: -------------------------------------------------------------------------------- 1 | # 第九章、开发中间件 2 | 3 | 在本章中,我们将涉及以下主题。 4 | 5 | * 使用中间件进行认证 6 | * 使用中间件实现访问控制 7 | * 使用高速缓存提高性能 8 | * 实施路由选择 9 | * 进行框架间的系统调用 10 | * 使用中间件来跨语言 11 | 12 | ## 前言 13 | 14 | 正如IT行业经常发生的那样,术语被发明出来,然后被使用和滥用。中间件这个词也不例外。可以说,这个术语的第一次使用是在2000年由互联网工程任务组(IETF)提出的。最初,这个术语适用于任何在传输层(即TCP/IP)和应用层之间操作的软件。最近,特别是随着PHP标准建议7(PSR-7)的接受,中间件,特别是PHP世界中的中间件,已经被应用于Web客户-服务器环境。 15 | 16 | {% hint style="info" %} 17 | 本节中的事例将使用附录《定义PSR-7类》中定义的具体类。 18 | {% endhint %} 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /mo-kuai-yi/di-liu-zhang-jian-li-ke-kuo-zhan-de-wang-zhan.md: -------------------------------------------------------------------------------- 1 | # 第六章、建立可扩展的网站 2 | 3 | -------------------------------------------------------------------------------- /mo-kuai-yi/di-liu-zhang-jian-li-ke-kuo-zhan-de-wang-zhan/README.md: -------------------------------------------------------------------------------- 1 | # 第六章、建立可扩展的网站 2 | 3 | 在这一章中,我们将讨论以下主题: 4 | 5 | * 创建通用表单元素生成器 6 | * 创建一个HTML单选元素生成器 7 | * 创建一个HTML选择元素生成器 8 | * 实现表单工厂 9 | * 链式 $\_POST 过滤器 10 | * 链式 $\_POST 验证器 11 | * 将验证绑定到表单 12 | 13 | ## 引言 14 | 15 | 在本章中,我们将向您展示如何构建生成HTML表单元素的类。通用元素生成器可以用于文本、文本区域、密码和类似的HTML输入类型。之后,我们将展示允许你用一个值数组预先配置元素的变体。表单工厂的示例将把所有这些生成器整合在一起,让您使用一个配置数组来渲染整个表单。最后,我们介绍允许过滤和验证输入的 `$_POST` 数据的示例。 16 | 17 | -------------------------------------------------------------------------------- /mo-kuai-yi/di-qi-zhang-fang-wen-web-fu-wu.md: -------------------------------------------------------------------------------- 1 | # 第七章、访问Web服务 2 | 3 | -------------------------------------------------------------------------------- /mo-kuai-yi/di-qi-zhang-fang-wen-web-fu-wu/README.md: -------------------------------------------------------------------------------- 1 | # 第七章、访问Web服务 2 | 3 | 在本章中,我们将介绍以下主题: 4 | 5 | * 在PHP和XML之间转换 6 | * 创建一个简单的REST客户端 7 | * 创建一个简单的REST服务器 8 | * 创建一个简单的SOAP客户端 9 | * 创建一个简单的SOAP服务器 10 | 11 | ## 引言 12 | 13 | 对外部网络服务进行后台查询正在成为任何PHP网络实践中越来越多的一部分。能够提供适当的、及时的、丰富的数据意味着为你的客户和你开发的网站带来更多的业务。我们首先介绍几个在可扩展标记语言(XML)和本地 PHP 之间进行数据转换的事例。接下来,我们将向您展示如何实现一个简单的代表状态传输(REST)客户端和服务器。之后,我们将注意力转向SOAP客户端和服务器。 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /mo-kuai-yi/di-qi-zhang-fang-wen-web-fu-wu/chuang-jian-yi-ge-jian-dan-de-soap-ke-hu-duan.md: -------------------------------------------------------------------------------- 1 | # 创建一个简单的SOAP客户端 2 | 3 | 与实现REST客户端或服务器的过程相比,使用SOAP是非常容易的,因为有一个PHP SOAP扩展提供了这两种功能。 4 | 5 | {% hint style="info" %} 6 | 一个经常被问到的问题是 "SOAP和REST之间有什么区别?" SOAP内部使用XML作为其数据格式。SOAP使用HTTP,但只用于传输,除此之外对其他HTTP方法无法进行识别。REST直接操作HTTP,可以使用任何数据格式,但首选JSON。另一个关键的区别是,SOAP可以与WSDL一起操作,这使得服务自我描述,从而更加公开。因此,SOAP服务通常由国家卫生组织等公共机构提供。 7 | {% endhint %} 8 | 9 | ## 如何做... 10 | 11 | 在这个例子中,我们将对美国国家气象服务提供的现有SOAP服务进行SOAP请求。 12 | 13 | 1.首先要考虑的是识别WSDL文档。WSDL是描述服务的XML文档。 14 | 15 | ```php 16 | $wsdl = 'http://graphical.weather.gov/xml/SOAP_server/' 17 | . 'ndfdXMLserver.php?wsdl'; 18 | ``` 19 | 20 | 2.接下来,我们使用 WSDL 创建一个 soap 客户端实例。 21 | 22 | ```php 23 | $soap = new SoapClient($wsdl, array('trace' => TRUE)); 24 | ``` 25 | 26 | 3.然后,我们可以自由地初始化一些变量,以应对天气预报的请求。 27 | 28 | ```php 29 | $units = 'm'; 30 | $params = ''; 31 | $numDays = 7; 32 | $weather = ''; 33 | $format = '24 hourly'; 34 | $startTime = new DateTime(); 35 | ``` 36 | 37 | 4. 然后,我们可以发出`LatLonListCityNames()`SOAP请求,在WSDL中被标识为一个操作,以获取服务支持的城市列表。该请求以 XML 格式返回,建议创建一个 `SimpleXLMElement` 实例。 38 | 39 | ```php 40 | $xml = new SimpleXMLElement($soap->LatLonListCityNames(1)); 41 | ``` 42 | 43 | 5. 不幸的是,城市列表和它们对应的经纬度是在单独的XML节点中。因此,我们使用`array_combine()`PHP函数来创建一个关联数组,其中经纬度是键,城市名称是值。然后我们可以使用这个数组来呈现一个HTML `SELECT`下拉列表,使用`asort()`来对列表进行字母排序。 44 | 45 | ```php 46 | $cityNames = explode('|', $xml->cityNameList); 47 | $latLonCity = explode(' ', $xml->latLonList); 48 | $cityLatLon = array_combine($latLonCity, $cityNames); 49 | asort($cityLatLon); 50 | ``` 51 | 52 | 6. 然后,我们可以从网络请求中获得城市数据,如下所示。 53 | 54 | ```php 55 | $currentLatLon = (isset($_GET['city'])) ? strip_tags(urldecode($_GET['city'])) : ''; 56 | ``` 57 | 58 | 7.我们希望进行的 SOAP 调用是 `NDFDgenByDay()`。我们可以通过检查 WSDL 来确定提供给 SOAP 服务器的参数的性质。 59 | 60 | ```php 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | ``` 70 | 71 | 8. 如果`$currentLatLon`的值被设置,我们就可以处理这个请求。我们用 `try {} catch {}` 块来处理请求,以防出现异常。 72 | 73 | ```php 74 | if ($currentLatLon) { 75 | list($lat, $lon) = explode(',', $currentLatLon); 76 | try { 77 | $weather = $soap->NDFDgenByDay($lat,$lon, 78 | $startTime->format('Y-m-d'),$numDays,$unit,$format); 79 | } catch (Exception $e) { 80 | $weather .= PHP_EOL; 81 | $weather .= 'Latitude: ' . $lat . ' | Longitude: ' . $lon; 82 | $weather .= 'ERROR' . PHP_EOL; 83 | $weather .= $e->getMessage() . PHP_EOL; 84 | $weather .= $soap->__getLastResponse() . PHP_EOL; 85 | } 86 | } 87 | ?> 88 | ``` 89 | 90 | ## 如何运行... 91 | 92 | 将前面所有的代码复制到`chap_07_simple_soap_client_weather_service.php`文件中。然后你可以添加视图逻辑来显示城市列表的表单以及结果。 93 | 94 | ```php 95 |
96 |
City List: 97 | 104 |
105 |
106 |
107 | 
108 | 
109 | ``` 110 | 111 | 这是在浏览器中请求俄亥俄州克利夫兰市天气预报的结果。 112 | 113 | ![](../../.gitbook/assets/image%20%28107%29.png) 114 | 115 | ## 参考 116 | 117 | 关于SOAP和REST之间的区别,请参考[http://stackoverflow.com/questions/209905/representational-state-transfer-rest-and-simple-object-access-protocol-soap?lq=1](http://stackoverflow.com/questions/209905/representational-state-transfer-rest-and-simple-object-access-protocol-soap?lq=1)。 118 | 119 | -------------------------------------------------------------------------------- /mo-kuai-yi/di-qi-zhang-fang-wen-web-fu-wu/zai-php-he-xml-zhi-jian-zhuan-huan.md: -------------------------------------------------------------------------------- 1 | # 在PHP和XML之间转换 2 | 3 | 当考虑PHP本地数据类型和XML之间的转换时,我们通常会将数组作为主要目标。考虑到这一点,从PHP数组到XML的转换过程与反过来的转换过程截然不同。 4 | 5 | {% hint style="info" %} 6 | 对象也可以考虑转换;但是,在XML中很难呈现对象方法。不过,可以通过使用`get_object_vars()`函数来表示属性,该函数将对象属性读入一个数组。 7 | {% endhint %} 8 | 9 | ## 如何做... 10 | 11 | 1.首先,我们定义一个`Application\Parse\ConvertXm`l类。这个类将持有将XML转换为PHP数组的方法,反之亦然。我们将需要SPL中的`SimpleXMLElement`和`SimpleXMLIterator`类。 12 | 13 | ```php 14 | namespace Application\Parse; 15 | use SimpleXMLIterator; 16 | use SimpleXMLElement; 17 | class ConvertXml 18 | { 19 | } 20 | ``` 21 | 22 | 2. 接下来,我们定义一个`xmlToArray()`方法,它将接受一个SimpleXMLIterator实例作为参数。它将被递归调用,并从一个XML文档中产生一个PHP数组。我们利用`SimpleXMLIterator`的能力在XML文档中前进,使用`key()`、`current()`、`next()`和`rewind()`方法来导航。 23 | 24 | ```php 25 | public function xmlToArray(SimpleXMLIterator $xml) : array 26 | { 27 | $a = array(); 28 | for( $xml->rewind(); $xml->valid(); $xml->next() ) { 29 | if(!array_key_exists($xml->key(), $a)) { 30 | $a[$xml->key()] = array(); 31 | } 32 | if($xml->hasChildren()){ 33 | $a[$xml->key()][] = $this->xmlToArray($xml->current()); 34 | } 35 | else{ 36 | $a[$xml->key()] = (array) $xml->current()->attributes(); 37 | $a[$xml->key()]['value'] = strval($xml->current()); 38 | } 39 | } 40 | return $a; 41 | } 42 | ``` 43 | 44 | 3. 对于反向过程,也叫递归,我们定义了两个方法。第一个方法`arrayToXml()`,设置一个初始`SimpleXMLElement`实例,然后调用第二个方法\`phpToXml\(\)。 45 | 46 | ```php 47 | public function arrayToXml(array $a) 48 | { 49 | $xml = new SimpleXMLElement( 50 | ''); 51 | $this->phpToXml($a, $xml); 52 | return $xml->asXML(); 53 | } 54 | ``` 55 | 56 | 4. 请注意,在第二个方法中,我们使用`get_object_vars()`来处理数组元素中的一个对象。你还会注意到,单独的数字是不允许作为XML标签的,这意味着要在数字前面添加一些文本。 57 | 58 | ```php 59 | protected function phpToXml($value, &$xml) 60 | { 61 | $node = $value; 62 | if (is_object($node)) { 63 | $node = get_object_vars($node); 64 | } 65 | if (is_array($node)) { 66 | foreach ($node as $k => $v) { 67 | if (is_numeric($k)) { 68 | $k = 'number' . $k; 69 | } 70 | if (is_array($v)) { 71 | $newNode = $xml->addChild($k); 72 | $this->phpToXml($v, $newNode); 73 | } elseif (is_object($v)) { 74 | $newNode = $xml->addChild($k); 75 | $this->phpToXml($v, $newNode); 76 | } else { 77 | $xml->addChild($k, $v); 78 | } 79 | } 80 | } else { 81 | $xml->addChild(self::UNKNOWN_KEY, $node); 82 | } 83 | } 84 | ``` 85 | 86 | ## 如何运行... 87 | 88 | 作为 XML 文档的示例,你可以使用美国国家气象局的 Web 服务定义语言(WSDL)。这是一个描述 SOAP 服务的 XML 文档,可以在 [http://graphical.weather.gov/xml/SOAP\_server/ndfdXMLserver.php?wsdl](http://graphical.weather.gov/xml/SOAP_server/ndfdXMLserver.php?wsdl) 找到。 89 | 90 | 我们将使用`SimpleXMLIterator`类来提供一个迭代机制,然后你可以配置自动加载,并得到一个`ApplicationParseConvertXml`的实例。使用`xmlToArray()`将WSDL转换为PHP数组。 91 | 92 | ```php 93 | require __DIR__ . '/../Application/Autoload/Loader.php'; 94 | Application\Autoload\Loader::init(__DIR__ . '/..'); 95 | use Application\Parse\ConvertXml; 96 | $wsdl = 'http://graphical.weather.gov/xml/' 97 | . 'SOAP_server/ndfdXMLserver.php?wsdl'; 98 | $xml = new SimpleXMLIterator($wsdl, 0, TRUE); 99 | $convert = new ConvertXml(); 100 | var_dump($convert->xmlToArray($xml)); 101 | ``` 102 | 103 | 由此产生的数组如图所示。 104 | 105 | ![](../../.gitbook/assets/image%20%2891%29.png) 106 | 107 | 要做相反的事情,使用本配方中描述的`arrayToXml()`方法。作为源文件,你可以使用`source/data/mongo.db.global.php`文件,该文件包含了一个通过O'Reilly Media提供的MongoDB培训视频的大纲(免责声明:由本作者提供!)。使用相同的自动加载器配置和`Application\Parse\ConvertXml`实例,这里是你可以使用的示例代码。 108 | 109 | ```php 110 | $convert = new ConvertXml(); 111 | header('Content-Type: text/xml'); 112 | echo $convert->arrayToXml(include CONFIG_FILE); 113 | ``` 114 | 115 | 这是在浏览器中的输出。 116 | 117 | ![](../../.gitbook/assets/image%20%2893%29.png) 118 | 119 | -------------------------------------------------------------------------------- /mo-kuai-yi/di-san-zhang-shi-yong-php-han-shu.md: -------------------------------------------------------------------------------- 1 | # 第三章、使用 PHP 函数 2 | 3 | -------------------------------------------------------------------------------- /mo-kuai-yi/di-san-zhang-shi-yong-php-han-shu/README.md: -------------------------------------------------------------------------------- 1 | # 第三章、使用 PHP 函数 2 | 3 | 在本章中,我们将讨论以下主题: 4 | 5 | * 函数开发 6 | * 数据类型提示 7 | * 使用返回值数据类型 8 | * 使用迭代器 9 | * 使用生成器编写自己的迭代器 10 | 11 | ## 引言 12 | 13 | 在本章中,我们将考虑利用 PHP 的**函数式编程能力**的示例。函数式编程,或者说**程序化编程**,是PHP代码在PHP第4版引入**面向对象编程**(**OOP**)之前的传统编写方式。函数式编程是一种编程范式—一种构建计算机程序结构和元素的风格—它将计算视为数学函数的评估,并避免改变状态和可变数据。然后这个文件可以包含在任何未来的脚本中,允许随意调用定义的函数。 14 | 15 | -------------------------------------------------------------------------------- /mo-kuai-yi/di-san-zhang-shi-yong-php-han-shu/shi-yong-fan-hui-zhi-shu-ju-lei-xing.md: -------------------------------------------------------------------------------- 1 | # 使用返回值数据类型 2 | 3 | PHP 7允许您为函数的返回值指定数据类型。 但是,与标量类型提示不同,您不需要添加任何特殊的声明。 4 | 5 | ## 如何做... 6 | 7 | 1.本示例说明如何将数据类型分配给函数返回值。 要分配返回数据类型,请首先按照通常的方式定义函数。 在右括号后,添加一个空格,然后添加数据类型和冒号: 8 | 9 | ```php 10 | function returnsString(DateTime $date, $format) : string 11 | { 12 | return $date->format($format); 13 | } 14 | ``` 15 | 16 | {% hint style="warning" %} 17 | PHP 7.1引入了关于返回数据类型的变体,称为**可空类型**。 您需要做的就是将 `string` 更改为 `?string` 。 这允许函数返回字符串或 `NULL` 。 18 | {% endhint %} 19 | 20 | 2.无论函数内部的数据类型如何,函数返回的所有内容都将转换为声明的数据类型作为返回值。 注意,在此示例中,将 `$a` , `$b` 和 `$c` 的值相加在一起以产生单个和,然后将其返回。 通常,您希望返回值是数字数据类型。 但是,在这种情况下,返回数据类型被声明为字符串,它覆盖了PHP的类型处理过程: 21 | 22 | ```php 23 | function convertsToString($a, $b, $c) : string 24 | 25 | return $a + $b + $c; 26 | } 27 | ``` 28 | 29 | 3.您还可以将类分配为返回数据类型。 在此示例中,我们分配了`DateTime` 的返回类型,该类型是PHP `DateTime` 扩展的一部分: 30 | 31 | ```php 32 | function makesDateTime($year, $month, $day) : DateTime 33 | { 34 | $date = new DateTime(); 35 | $date->setDate($year, $month, $day); 36 | return $date; 37 | } 38 | ``` 39 | 40 | {% hint style="warning" %} 41 | `makeDateTime()` 函数可能是标量类型提示的潜在候选者。 如果 `$year` , `$month` 或 `$day`不是整数,则在调用 `setDate()` 时会生成警告。 如果使用标量类型提示,并且传递了错误的数据类型,则会引发 `TypeError` 。 虽然是否发出警告或引发 `TypeError` 确实无关紧要,但至少 `TypeError` 会导致错误使用您代码的开发人员坐立不安! 42 | {% endhint %} 43 | 44 | 4.如果一个函数具有返回数据类型,而您在函数代码中返回了错误的数据类型,则在运行时将引发 `TypeError` 。 此函数指定 `DateTime` 的返回类型,但返回一个字符串。 当PHP引擎检测到差异时,将引发 `TypeError` ,但要等到运行时才会报错: 45 | 46 | ```php 47 | function wrongDateTime($year, $month, $day) : DateTime 48 | { 49 | return date($year . '-' . $month . '-' . $day); 50 | } 51 | ``` 52 | 53 | {% hint style="warning" %} 54 | 如果返回数据类型类不是内置的PHP类(也就是SPL中的一个类),你需要确保该类已经被自动加载,或者被包含。 55 | {% endhint %} 56 | 57 | ## 如何运行... 58 | 59 | 首先,将前面提到的函数放入一个名为 `chap_03_developing_functions_return_types_library.php` 的库文件中。这个文件需要包含在调用这些函数的 `chap_03_developing_functions_return_types.php` 脚本中。 60 | 61 | ```php 62 | include (__DIR__ . '/chap_03_developing_functions_return_types_library.php'); 63 | ``` 64 | 65 | 现在,您可以调用 `returnString()` ,提供一个 `DateTime` 实例和一个格式化字符串: 66 | 67 | ```php 68 | $date = new DateTime(); 69 | $format = 'l, d M Y'; 70 | $now = returnsString($date, $format); 71 | echo $now . PHP_EOL; 72 | var_dump($now); 73 | ``` 74 | 75 | 如预期的那样,输出为字符串: 76 | 77 | ![](../../.gitbook/assets/image%20%2821%29.png) 78 | 79 | 现在,您可以调用 `convertsToString()` 并提供三个整数作为参数。 请注意,返回类型为字符串: 80 | 81 | ```php 82 | echo "\nconvertsToString()\n"; 83 | var_dump(convertsToString(2, 3, 4)); 84 | ``` 85 | 86 | ![](../../.gitbook/assets/image%20%2817%29.png) 87 | 88 | 为了说明这一点,您可以将一个类分配为返回值,请使用三个整数参数调用 `makeDateTime()` : 89 | 90 | ```php 91 | echo "\nmakesDateTime()\n"; 92 | $d = makesDateTime(2015, 11, 21); 93 | var_dump($d); 94 | ``` 95 | 96 | ![](../../.gitbook/assets/image%20%2816%29.png) 97 | 98 | 最后,使用三个整数参数调用 `rongDateTime()` : 99 | 100 | ```php 101 | try { 102 | $e = wrongDateTime(2015, 11, 21); 103 | var_dump($e); 104 | } catch (TypeError $e) { 105 | echo $e->getMessage(); 106 | } 107 | ``` 108 | 109 | 请注意,在运行时会引发 `TypeError` : 110 | 111 | ![](../../.gitbook/assets/image%20%2820%29.png) 112 | 113 | ## 更多... 114 | 115 | PHP 7.1添加了一个新的返回值类型 `void` 。 当您不希望从函数中返回任何值时,将使用此方法。 有关更多信息,请参阅[https://wiki.php.net/rfc/void\_return\_type](https://wiki.php.net/rfc/void_return_type)。 116 | 117 | ## 参考 118 | 119 | 有关返回类型声明的更多信息,请参见以下文章: 120 | 121 | * [http://php.net/manual/en/functions.arguments.php\#functions.arguments.type-declaration.strict](http://php.net/manual/en/functions.arguments.php#functions.arguments.type-declaration.strict) 122 | * [https://wiki.php.net/rfc/return\_types](https://wiki.php.net/rfc/return_types) 123 | 124 | 有关可为空的类型的信息,请参考本文: 125 | 126 | [https://wiki.php.net/rfc/nullable\_types](https://wiki.php.net/rfc/nullable_types) 127 | 128 | -------------------------------------------------------------------------------- /mo-kuai-yi/di-san-zhang-shi-yong-php-han-shu/shi-yong-sheng-cheng-qi-bian-xie-zi-ji-de-die-dai-qi.md: -------------------------------------------------------------------------------- 1 | # 使用生成器编写自己的迭代器 2 | 3 | 在前面的示例中,我们演示了如何使用 PHP 7 SPL 中提供的迭代器。但是,如果示例不能提供给你一个给定项目所需要的东西呢?一个解决方案是开发一个函数,它不是建立一个数组然后返回,而是使用 `yield` 关键字通过迭代的方式逐步返回值。这样的函数被称为**生成器**。事实上,在后台,PHP引擎会自动将你的函数转换为一个名为 `Generator` 的特殊内置类。 4 | 5 | 这种方法有几个优点。主要的好处是当你有一个大的容器要遍历时(也就是解析一个庞大的文件)。传统的方法是建立一个数组,然后返回这个数组。这样做的问题是,你实际上是把所需的内存量增加了一倍! 同时,性能也会受到影响,因为只有在返回最终数组后才会有结果。 6 | 7 | ## 如何做... 8 | 9 | 1.在此示例中,我们在基于迭代器的函数库的基础上,添加了我们自己设计的生成器。 在这种情况下,我们将重复上面关于迭代器的部分中描述的功能,在这些迭代器中,我们堆叠了`ArrayIterator` , `FilterIterator` 和 `LimitIterator`。 10 | 11 | 2.因为我们需要访问源数组,所需的过滤器,页数和每页项数,所以我们将适当的参数包含在单个 `filterResultsGenerator()` 函数中。 然后,我们根据页码和限制(即每页的项目数)计算偏移量。 接下来,我们遍历数组,应用过滤器,如果尚未达到偏移量,则继续循环;如果已达到极限,则中断: 12 | 13 | ```php 14 | function filteredResultsGenerator(array $array, $filter, $limit = 10, $page = 0) 15 | { 16 | $max = count($array); 17 | $offset = $page * $limit; 18 | foreach ($array as $key => $value) { 19 | if (!stripos($value, $filter) !== FALSE) continue; 20 | if (--$offset >= 0) continue; 21 | if (--$limit <= 0) break; 22 | yield $value; 23 | } 24 | } 25 | ``` 26 | 27 | 3.您会注意到此函数与其他函数之间的主要区别是 `yield` 关键字。 此关键字的作用是通知PHP引擎生成 `Generator` 实例并封装代码。 28 | 29 | ## 如何运行... 30 | 31 | 为了演示 `filteredResultsGenerator()` 函数的用法,我们将实现一个Web应用程序,扫描一个网页,并产生一个从 `HREF` 属性中筛选出来的URLs的分页列表。 32 | 33 | 首先,您需要将 `filteredResultsGenerator()` 函数的代码添加到先前示例中使用的库文件中,然后将前面描述的函数放入包含文件 `chap_03_developing_functions_iterators_library.php` 中。 34 | 35 | 接下来,定义一个测试脚本,`chap_03_developing_functions_using_generator.php` ,它既包括函数库,也包括定义 `Application\Web\Hoover` 的文件。 36 | 37 | ```php 38 | include (__DIR__ . DIRECTORY_SEPARATOR . 'chap_03_developing_functions_iterators_library.php'); 39 | include (__DIR__ . '/../Application/Web/Hoover.php'); 40 | ``` 41 | 42 | 然后,您将需要从用户那里收集有关要扫描的URL,用作筛选器的字符串,每页多少个项目以及当前页码的输入。 43 | 44 | {% hint style="warning" %} 45 | 空合并操作符(`??`)是从Web获取输入的理想选择。 如果未定义,它不会生成任何通知。 如果未从用户输入接收到该参数,则可以提供默认值。 46 | {% endhint %} 47 | 48 | ```php 49 | $url = trim(strip_tags($_GET['url'] ?? '')); 50 | $filter = trim(strip_tags($_GET['filter'] ?? '')); 51 | $limit = (int) ($_GET['limit'] ?? 10); 52 | $page = (int) ($_GET['page'] ?? 0); 53 | ``` 54 | 55 | {% hint style="info" %} 56 | **最佳实践** 57 | 58 | 网络安全应该永远是一个优先考虑的问题。在这个例子中,您可以使用 `strip_tags()`,也可以强制将数据类型改为整数 `(int)`,作为对用户输入进行清理的措施。 59 | {% endhint %} 60 | 61 | 然后您就可以定义分页列表中上一页和下一页的链接中使用的变量。请注意,您也可以应用理智性检查,以确保下一页不会从结果集的末尾离开。为了简洁起见,在这个例子中没有应用这种理智检查: 62 | 63 | ```php 64 | $next = $page + 1; 65 | $prev = $page - 1; 66 | $base = '?url=' . htmlspecialchars($url) 67 | . '&filter=' . htmlspecialchars($filter) 68 | . '&limit=' . $limit 69 | . '&page='; 70 | ``` 71 | 72 | 然后,我们需要创建一个 `Application\Web\Hoover`实例,并从目标URL中获取HREF属性: 73 | 74 | ```php 75 | $vac = new Application\Web\Hoover(); 76 | $list = $vac->getAttribute($url, 'href'); 77 | ``` 78 | 79 | 最后,我们定义HTML输出,渲染一个输入表单,并通过前面描述的 `htmlList()` 函数运行我们的生成器: 80 | 81 | ```php 82 |
83 | 84 | 85 | 86 | 90 | 91 | 92 | 93 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 109 | 110 |
URL 87 | 89 |
Filter 94 |
Limit
 
  107 | <-- PREV | 108 | NEXT -->
111 |
112 |
113 | 115 | ``` 116 | 117 | 这是输出示例: 118 | 119 | ![](../../.gitbook/assets/image%20%2810%29.png) 120 | 121 | -------------------------------------------------------------------------------- /mo-kuai-yi/di-shi-er-zhang-ti-gao-wang-zhan-an-quan.md: -------------------------------------------------------------------------------- 1 | # 第十二章、提高网站安全 2 | 3 | 在本章中,我们将涉及以下主题。 4 | 5 | * 过滤$\_POST数据 6 | * 验证$\_POST数据 7 | * 保护PHP会话 8 | * 用令牌保护表格的安全 9 | * 建立一个安全的密码生成器 10 | * 带有验证码的安全保护表格 11 | * 不使用mcrypt进行加密/解密 12 | 13 | ## 前言 14 | 15 | 在这一章中,我们将向您展示如何设置一个简单而有效的机制来过滤和验证一个帖子数据块,然后,我们将介绍如何保护您的PHP会话免受潜在的会话劫持和其他形式的攻击。下一个示例将介绍如何使用随机生成的令牌来保护表单免受**跨站点请求伪造(CSRF)**攻击。关于密码生成的示例向您展示了如何结合 PHP 7 真正的随机化来生成安全的密码。然后我们向您展示了两种形式的验证码:一种是基于文本的,另一种是使用扭曲的图像。最后,还有一个秘诀,它涵盖了强加密,而不需要使用信誉不佳和即将被淘汰的 `mcrypt` 扩展。 16 | 17 | -------------------------------------------------------------------------------- /mo-kuai-yi/di-shi-er-zhang-ti-gao-wang-zhan-an-quan/README.md: -------------------------------------------------------------------------------- 1 | # 第十二章、提高网站安全 2 | 3 | 在本章中,我们将涉及以下主题。 4 | 5 | * 过滤$\_POST数据 6 | * 验证$\_POST数据 7 | * 保护PHP session 8 | * 用令牌保护表格的安全 9 | * 建立一个安全的密码生成器 10 | * 带有验证码的安全保护表格 11 | * 不使用mcrypt进行加密/解密 12 | 13 | ## 前言 14 | 15 | 在这一章中,我们将向您展示如何设置一个简单而有效的机制来过滤和验证一个帖子数据块,然后,我们将介绍如何保护您的PHP session 免受潜在的会话劫持和其他形式的攻击。下一个示例将介绍如何使用随机生成的令牌来保护表单免受**跨站点请求伪造(CSRF)**攻击。关于密码生成的示例向您展示了如何结合 PHP 7 真正的随机化来生成安全的密码。然后我们向您展示了两种形式的验证码:一种是基于文本的,另一种是使用扭曲的图像。最后,还有一个秘诀,它涵盖了强加密,而不需要使用信誉不佳和即将被淘汰的 `mcrypt` 扩展。 16 | 17 | -------------------------------------------------------------------------------- /mo-kuai-yi/di-shi-er-zhang-ti-gao-wang-zhan-an-quan/yan-zheng-post-shu-ju.md: -------------------------------------------------------------------------------- 1 | # 验证$\_POST数据 2 | 3 | 过滤和验证的主要区别在于后者不改变原始数据。另一个区别在于意图。验证的目的是确认数据是否符合根据客户需求建立的某些标准。 4 | 5 | ## 如何做... 6 | 7 | 1.我们将在这里介绍的基本验证机制与前面的事例中所示的相同。与过滤一样,了解要验证的数据的性质,它如何符合客户的要求,以及它是否符合数据库执行的标准是至关重要的。例如,如果在数据库中,列的最大宽度是128,那么验证回调可以使用`strlen()`来确认提交的数据长度是否小于或等于128个字符。同样,可以根据情况使用`ctype_alnum()`来确认数据只包含字母和数字。 8 | 9 | 2. 验证的另一个考虑因素是呈现一个适当的验证失败信息。验证过程在一定意义上也是一个确认过程,大概会有人对验证进行审核,确认成功或失败。如果验证失败,这个人需要知道原因。 10 | 11 | 3. 在这个例子中,我们将再次关注`prospects`表。现在我们可以将所需的PHP函数集归为一个回调数组。下面是一个基于表单数据验证需求的例子,表单数据最终将被存储在`prospects`表中。 12 | 13 | ```php 14 | $validator = [ 15 | 'email' => [ 16 | 'callback' => function ($item) { 17 | return filter_var($item, FILTER_VALIDATE_EMAIL); }, 18 | 'message' => 'Invalid email address'], 19 | 'alpha' => [ 20 | 'callback' => function ($item) { 21 | return ctype_alpha(str_replace(' ', '', $item)); }, 22 | 'message' => 'Data contains non-alpha characters'], 23 | 'alnum' => [ 24 | 'callback' => function ($item) { 25 | return ctype_alnum(str_replace(' ', '', $item)); }, 26 | 'message' => 'Data contains characters which are ' 27 | . 'not letters or numbers'], 28 | 'digits' => [ 29 | 'callback' => function ($item) { 30 | return preg_match('/[^0-9.]/', $item); }, 31 | 'message' => 'Data contains characters which ' 32 | . 'are not numbers'], 33 | 'length' => [ 34 | 'callback' => function ($item, $length) { 35 | return strlen($item) <= $length; }, 36 | 'message' => 'Item has too many characters'], 37 | 'upper' => [ 38 | 'callback' => function ($item) { 39 | return $item == strtoupper($item); }, 40 | 'message' => 'Item is not upper case'], 41 | 'phone' => [ 42 | 'callback' => function ($item) { 43 | return preg_match('/[^0-9() -+]/', $item); }, 44 | 'message' => 'Item is not a valid phone number'], 45 | ]; 46 | ``` 47 | 48 | {% hint style="info" %} 49 | 请注意,对于alpha和alnum回调,我们首先使用`str_replace()`删除空白字符。然后我们可以调用`ctype_alpha()`或`ctype_alnum()`,这将决定是否存在任何不允许的字符。 50 | {% endhint %} 51 | 52 | 4. 接下来,我们定义一个与`$_POST`中的字段名相匹配的赋值数组。在这个数组中,我们指定了`$validator`数组中的key,以及任何参数。 53 | 54 | ```php 55 | $assignments = [ 56 | 'first_name' => ['length' => 32, 'alpha' => NULL], 57 | 'last_name' => ['length' => 32, 'alpha' => NULL], 58 | 'address' => ['length' => 64, 'alnum' => NULL], 59 | 'city' => ['length' => 32, 'alnum' => NULL], 60 | 'state_province'=> ['length' => 20, 'alpha' => NULL], 61 | 'postal_code' => ['length' => 12, 'alnum' => NULL], 62 | 'phone' => ['length' => 12, 'phone' => NULL], 63 | 'country' => ['length' => 2, 'alpha' => NULL, 64 | 'upper' => NULL], 65 | 'email' => ['length' => 128, 'email' => NULL], 66 | 'budget' => ['digits' => NULL], 67 | ]; 68 | ``` 69 | 70 | 5. 然后,我们使用嵌套的`foreach()`循环,一次一个字段地迭代数据块。对于每个字段,我们都会循环执行分配给该字段的回调。 71 | 72 | ```php 73 | foreach ($data as $field => $item) { 74 | echo 'Processing: ' . $field . PHP_EOL; 75 | foreach ($assignments[$field] as $key => $option) { 76 | if ($validator[$key]['callback']($item, $option)) { 77 | $message = 'OK'; 78 | } else { 79 | $message = $validator[$key]['message']; 80 | } 81 | printf('%8s : %s' . PHP_EOL, $key, $message); 82 | } 83 | } 84 | ``` 85 | 86 | {% hint style="info" %} 87 | 与其直接呼应输出,不如如图所示,你可以将验证成功/失败的信息记录下来,以便在稍后的时间提交给审核者。另外,如第6章 "建立可扩展网站" 中所示,你可以将验证机制工作到表单中,在其匹配的表单元素旁边显示验证消息。 88 | {% endhint %} 89 | 90 | ## 如何运行... 91 | 92 | 将步骤3到步骤5中的代码放入一个名为`chap_12_post_data_validation_basic.php`的文件中。你还需要定义一个数据数组来模拟`$_POST`中的数据。在这种情况下,你需要使用前面提到的两个数组,一个是好数据,一个是坏数据。最后的输出应该是这样的。 93 | 94 | ![](../../.gitbook/assets/image%20%28180%29.png) 95 | 96 | ## 更多... 97 | 98 | 在第6章 "构建可扩展网站 "中,题为 "链式$\_POST验证器 "的事例讨论了如何将这里所涵盖的基本验证概念融入到一个全面的过滤器链式机制中。 99 | 100 | -------------------------------------------------------------------------------- /mo-kuai-yi/di-shi-san-zhang-zui-jia-shi-jian-ce-shi-he-tiao-shi.md: -------------------------------------------------------------------------------- 1 | # 第十三章、最佳实践、测试和调试 2 | 3 | -------------------------------------------------------------------------------- /mo-kuai-yi/di-shi-san-zhang-zui-jia-shi-jian-ce-shi-he-tiao-shi/README.md: -------------------------------------------------------------------------------- 1 | # 第十三章、最佳实践、测试和调试 2 | 3 | 在本章中,我们将涉及以下主题。 4 | 5 | * 使用特征和接口 6 | * 通用异常处理程序 7 | * 通用错误处理程序 8 | * 编写一个简单的测试 9 | * 编写测试套件 10 | * 生成虚假的测试数据 11 | * 使用session\_start参数自定义会话 12 | 13 | ## 前言 14 | 15 | 在本章中,我们将向您展示特征和接口是如何一起工作的。然后,我们将注意力转移到回退机制的设计上,该机制将在你不能(或忘记)定义特定的`try/catch`块的情况下捕获错误和异常。然后,我们将冒险进入单元测试的世界,首先向您展示如何编写简单的测试,然后如何将这些测试组合成测试套件。接下来,我们定义了一个类,让你可以创建任意数量的通用测试数据。在本章的最后,我们将讨论如何使用 PHP 7 的新特性轻松管理会话。 16 | 17 | -------------------------------------------------------------------------------- /mo-kuai-yi/di-shi-san-zhang-zui-jia-shi-jian-ce-shi-he-tiao-shi/bian-xie-ce-shi-tao-jian.md: -------------------------------------------------------------------------------- 1 | # 编写测试套件 2 | 3 | 你可能已经注意到了,在阅读完前面的事例后,手动运行phpunit并指定测试类和PHP文件名会很快变得乏味。尤其是在处理有几十个甚至上百个类和文件的应用程序时,这种情况更加明显。PHPUnit 项目有一个内置的功能,可以用一条命令处理多个测试。这样一组测试被称为测试套件。 4 | 5 | ## 如何做... 6 | 7 | 1.最简单的是,你需要做的就是把所有的测试移到一个单独的文件夹里。 8 | 9 | ```php 10 | mkdir tests 11 | cp *Test.php tests 12 | ``` 13 | 14 | 2. 你需要调整包含或需要外部文件的命令,以说明新的位置。所示的例子(`SimpleTest`)是在前面的事例中开发的。 15 | 16 | ```php 17 | 50 | 51 | 52 | SimpleTest.php 53 | SimpleDbTest.php 54 | SimpleClassTest.php 55 | 56 | 57 | 58 | ``` 59 | 60 | 7. 下面是另一个基于目录运行测试的例子,也指定了一个引导文件。 61 | 62 | ```markup 63 | 64 | 65 | 66 | Simple 67 | 68 | 69 | 70 | ``` 71 | 72 | ## 如何运行... 73 | 74 | 确保所有的测试都已经定义好了,在前面的 "编写一个简单的测试 "中已经讨论过了,然后你可以创建一个测试文件夹,并将所有的`Test.php`_文件移动或复制到这个文件夹中。然后你可以创建一个测试文件夹,并将所有`Test.php`_文件移动或复制到这个文件夹中。然后你需要调整_\`_require\_once\`语句中的路径,如步骤2所示。 75 | 76 | ```bash 77 | phpunit tests 78 | ``` 79 | 80 | 你应该看到以下输出。 81 | 82 | ![](../../.gitbook/assets/image%20%28158%29.png) 83 | 84 | 为了演示通过`bootstrap`文件来使用自动加载,创建一个新的`test_with_autoload`目录。在这个文件夹中,定义一个`bootstrap.php`文件,代码如步骤5所示。在 `tests_with_autoload` 中创建两个目录。`Demo`和`Simple`。 85 | 86 | 从包含本章源代码的目录中,将该文件\(在前面的第12步中讨论过\)复制到`test_with_autoload/Demo/Demo.php`中。在开头的`demo = new Demo(); 106 | } 107 | // etc. 108 | ``` 109 | 110 | 之后,创建一个 `tests_with_autoload/phpunit.xml` 文件,把所有的东西整合在一起。 111 | 112 | ```markup 113 | 114 | 115 | 116 | Simple 117 | 118 | 119 | 120 | ``` 121 | 122 | 最后,改到包含本章代码的目录。现在你可以运行一个单元测试,其中包含一个bootstrap文件,以及自动加载和命名空间,如下所示。 123 | 124 | ```bash 125 | phpunit -c tests_with_autoload/phpunit.xml 126 | ``` 127 | 128 | 输出结果应如下所示: 129 | 130 | ![](../../.gitbook/assets/image%20%28192%29.png) 131 | 132 | ## 更多... 133 | 134 | 关于编写PHPUnit测试套件的更多信息,请看这个文档页:https://phpunit.de/manual/current/en/phpunit-book.html\#organizing-tests.xml-configuration。 135 | 136 | -------------------------------------------------------------------------------- /mo-kuai-yi/di-shi-san-zhang-zui-jia-shi-jian-ce-shi-he-tiao-shi/shi-yong-sessionstart-can-shu-zi-ding-yi-hui-hua.md: -------------------------------------------------------------------------------- 1 | # 使用session\_start参数自定义会话 2 | 3 | 在 PHP 7 之前,为了覆盖 `php.ini` 的安全会话管理设置,你必须使用一系列 `ini_set()` 命令。这种方法非常烦人,因为你需要知道哪些设置是可用的,而且很难在其他应用程序中重复使用相同的设置。然而,从 PHP 7 开始,你可以向 `session_start()` 命令提供一个参数数组,它可以立即设置这些值。 4 | 5 | ## 如何做... 6 | 7 | 1.我们首先开发一个`Application\Security\SessOptions`类,该类将持有会话参数,并有能力启动会话。我们还定义了一个类常量,以防传递无效的会话选项。 8 | 9 | ```php 10 | namespace Application\Security; 11 | use ReflectionClass; 12 | use InvalidArgumentsException; 13 | class SessOptions 14 | { 15 | const ERROR_PARAMS = 'ERROR: invalid session options'; 16 | ``` 17 | 18 | 2. 接下来,我们扫描`php.ini`会话指令列表\(在http://php.net/manual/en/session.configuration.php\)。我们特别要寻找那些在`Changeable`列中标记为`PHP_INI_ALL`的指令。这些指令可以在运行时被覆盖,因此可以作为 `session_start()` 的参数。 19 | 20 | ![](../../.gitbook/assets/image%20%28176%29.png) 21 | 22 | 3. 然后,我们将这些定义为类常量,这将使这个类在开发时更加可用。大多数像样的代码编辑器都能够扫描该类,并给出一个常量列表,从而使管理会话设置变得容易。请注意,为了节省本书的空间,并没有显示所有的设置。 23 | 24 | ```php 25 | const SESS_OP_NAME = 'name'; 26 | const SESS_OP_LAZY_WRITE = 'lazy_write'; // AVAILABLE // SINCE PHP 7.0.0. 27 | const SESS_OP_SAVE_PATH = 'save_path'; 28 | const SESS_OP_SAVE_HANDLER = 'save_handler'; 29 | // etc. 30 | ``` 31 | 32 | 4. 然后我们就可以定义构造函数,它接受一个包含`php.ini`会话设置的数组作为参数。我们使用`ReflectionClass`来获取一个类常量列表,并通过循环运行`$options`参数来确认设置是否被允许。同时注意到`array_flip()`的使用,它可以翻转键和值,这样我们的类常量的实际值就形成了数组键,而类常量的名字就变成了值。 33 | 34 | ```php 35 | protected $options; 36 | protected $allowed; 37 | public function __construct(array $options) 38 | { 39 | $reflect = new ReflectionClass(get_class($this)); 40 | $this->allowed = $reflect->getConstants(); 41 | $this->allowed = array_flip($this->allowed); 42 | unset($this->allowed[self::ERROR_PARAMS]); 43 | foreach ($options as $key => $value) { 44 | if(!isset($this->allowed[$key])) { 45 | error_log(__METHOD__ . ':' . self::ERROR_PARAMS); 46 | throw new InvalidArgumentsException( 47 | self::ERROR_PARAMS); 48 | } 49 | } 50 | $this->options = $options; 51 | } 52 | ``` 53 | 54 | 5. 然后,我们再用两个方法来结束;一个方法让我们可以访问外部允许的参数,而另一个方法则启动会话。 55 | 56 | ```php 57 | public function getAllowed() 58 | { 59 | return $this->allowed; 60 | } 61 | 62 | public function start() 63 | { 64 | session_start($this->options); 65 | } 66 | ``` 67 | 68 | ## 如何运行... 69 | 70 | 将本事例中讨论的所有代码放入`Application\Security`目录下的`SessOptions.php`文件中。然后你可以定义一个名为`chap_13_session_options.php`的调用程序来测试新的类,它设置了自动加载并使用了该类。 71 | 72 | ```php 73 | 1, 84 | SessOptions::SESS_OP_COOKIE_LIFETIME => 300, 85 | SessOptions::SESS_OP_COOKIE_HTTPONLY => 1, 86 | SessOptions::SESS_OP_NAME => 'UNLIKELYSOURCE', 87 | SessOptions::SESS_OP_SAVE_PATH => __DIR__ . '/session' 88 | ]; 89 | ``` 90 | 91 | 现在你可以创建`SessOptions`实例并运行`start()`来启动会话。你可以在这里使用`phpinfo()`来显示会话的一些信息。 92 | 93 | ```php 94 | $sessOpt = new SessOptions($options); 95 | $sessOpt->start(); 96 | $_SESSION['test'] = 'TEST'; 97 | phpinfo(INFO_VARIABLES); 98 | ``` 99 | 100 | 如果你用浏览器的开发工具查找cookie的信息,你会注意到名称被设置为`UNLIKELYSOURCE`,到期时间是5分钟以后。 101 | 102 | ![](../../.gitbook/assets/image%20%28204%29.png) 103 | 104 | 如果你对会话目录进行扫描,你会看到会话信息已经存储在那里。 105 | 106 | ![](../../.gitbook/assets/image%20%28201%29.png) 107 | 108 | ## 更多... 109 | 110 | 关于更多与session相关的php.ini指令的信息,请参见这个摘要:http://php.net/manual/en/session.configuration.php。 111 | 112 | -------------------------------------------------------------------------------- /mo-kuai-yi/di-shi-san-zhang-zui-jia-shi-jian-ce-shi-he-tiao-shi/tong-yong-cuo-wu-chu-li-cheng-xu.md: -------------------------------------------------------------------------------- 1 | # 通用错误处理程序 2 | 3 | 开发通用错误处理程序的过程与前面的配方非常相似。但是有一些不同之处。首先,在 PHP 7 中,有些错误是被抛出的,并且可以被捕获,而其他错误则会让你的应用程序停止运行。更加让人困惑的是,有些错误被当作异常处理,而其他错误则是由新的 PHP 7 `Error` 类衍生出来的。幸运的是,在 PHP 7 中,`Error` 和 `Exception` 都实现了一个叫做 `Throwable` 的新接口。因此,如果你不确定你的代码会抛出`Exception`还是`Error`,只需捕获一个`Throwable`的实例,就可以同时捕获这两种情况。 4 | 5 | ## 如何做... 6 | 7 | 1.修改前面事例中定义的`Application\Error\Handler`类。在构造函数中,设置一个新的`errorHandler()`方法作为默认的错误处理程序。 8 | 9 | ```php 10 | public function __construct($logFileDir = NULL, $logFile = NULL) 11 | { 12 | $logFile = $logFile ?? date('Ymd') . '.log'; 13 | $logFileDir = $logFileDir ?? __DIR__; 14 | $this->logFile = $logFileDir . '/' . $logFile; 15 | $this->logFile = str_replace('//', '/', $this->logFile); 16 | set_exception_handler([$this,'exceptionHandler']); 17 | set_error_handler([$this, 'errorHandler']); 18 | } 19 | ``` 20 | 21 | 2. 然后我们使用文档中的参数定义新方法。就像我们的异常处理程序一样,我们将信息记录到一个日志文件中。 22 | 23 | ```php 24 | public function errorHandler($errno, $errstr, $errfile, $errline) 25 | { 26 | $message = sprintf('ERROR: %s : %d : %s : %s : %s' . PHP_EOL, 27 | date('Y-m-d H:i:s'), $errno, $errstr, $errfile, $errline); 28 | file_put_contents($this->logFile, $message, FILE_APPEND); 29 | } 30 | ``` 31 | 32 | 3. 另外,为了能够区分错误和异常,在`exceptionHandler()`方法中向日志文件发送的消息中加入`exception`。 33 | 34 | ```php 35 | public function exceptionHandler($ex) 36 | { 37 | $message = sprintf('EXCEPTION: %19s : %20s : %s' . PHP_EOL, 38 | date('Y-m-d H:i:s'), get_class($ex), $ex->getMessage()); 39 | file_put_contents($this->logFile, $message, FILE_APPEND); 40 | } 41 | ``` 42 | 43 | ## 如何运行... 44 | 45 | 首先,对前面定义的`Application\Error\Handler`进行修改。接下来,创建一个抛出错误的类,在这个例子中,可以定义为`Application\Error\ThrowsError`。例如,你可以有一个方法试图进行除以零的操作,另一个方法试图使用`eval()`来解析非PHP代码。 46 | 47 | ```php 48 | zero = 1 / 0; 56 | } 57 | public function willNotParse() 58 | { 59 | eval(self::NOT_PARSE); 60 | } 61 | } 62 | ``` 63 | 64 | 然后你可以定义一个名为`chap_13_error_throwable.php`的调用程序,设置自动加载,使用相应的类,并创建`ThrowsError`的实例。 65 | 66 | ```php 67 | divideByZero(); 78 | $error->willNotParse(); 79 | echo 'Application continues ... ' . PHP_EOL; 80 | ``` 81 | 82 | 因为这是一个错误,程序执行停止,你不会看到应用程序继续。 83 | 84 | ![](../../.gitbook/assets/image%20%28162%29.png) 85 | 86 | 如果将方法调用包裹在`try/catch`块中,并抓取`Throwable`,则代码会继续执行。 87 | 88 | ```php 89 | try { 90 | $error->divideByZero(); 91 | } catch (Throwable $e) { 92 | echo 'Error Caught: ' . get_class($e) . ':' 93 | . $e->getMessage() . PHP_EOL; 94 | } 95 | try { 96 | $error->willNotParse(); 97 | } catch (Throwable $e) { 98 | echo 'Error Caught: ' . get_class($e) . ':' 99 | . $e->getMessage() . PHP_EOL; 100 | } 101 | echo 'Application continues ... ' . PHP_EOL; 102 | ``` 103 | 104 | 从下面的输出中,你还会注意到,程序退出时,代码为0,这说明一切正常。 105 | 106 | ![](../../.gitbook/assets/image%20%28177%29.png) 107 | 108 | 最后,在`try/catch`块之后,再次运行错误,将echo语句移到最后。你将在输出中看到错误被捕获,但在日志文件中,注意到`DivisionByZeroError`是由异常处理程序捕获的,而`ParseError`是由错误处理程序捕获的。 109 | 110 | ```php 111 | $handler = new Handler(__DIR__ . '/logs'); 112 | $error->divideByZero(); 113 | $error->willNotParse(); 114 | echo 'Application continues ... ' . PHP_EOL; 115 | ``` 116 | 117 | ![](../../.gitbook/assets/image%20%28152%29.png) 118 | 119 | ## 更多... 120 | 121 | PHP 7.1 允许在 `catch()`子句中指定多个类,因此,可以用 `catch (Exception | Error $e) { xxx }`代替单个 `Throwable`。 122 | 123 | -------------------------------------------------------------------------------- /mo-kuai-yi/di-shi-yi-zhang-ruan-jian-she-ji-mo-shi-de-shi-xian.md: -------------------------------------------------------------------------------- 1 | # 第十一章、软件设计模式的实现 2 | 3 | -------------------------------------------------------------------------------- /mo-kuai-yi/di-shi-yi-zhang-ruan-jian-she-ji-mo-shi-de-shi-xian/README.md: -------------------------------------------------------------------------------- 1 | # 第十一章、软件设计模式的实现 2 | 3 | 在本章中,我们将介绍以下主题: 4 | 5 | * 创建数组到对象的转化器 6 | * 构建对象到数组到转化器 7 | * 实施策略模式 8 | * 定义一个映射器 9 | * 实现对象关系映射 10 | * 实施发布/订阅设计模式 11 | 12 | ## 前言 13 | 14 | 将软件设计模式融入到面向对象编程(OOP)代码中的想法,最早是在1994年由著名的 "四人帮"(E.Gamma,R.Helm,R.Johnson和J.Vlissides)撰写的《设计模式:可复用面向对象软件设计》中提出。这项工作既没有定义标准,也没有定义协议,它确定了多年来证明有用的通用软件设计。本书所讨论的模式一般被认为可以分为三类:创造型、结构型和行为型。 15 | 16 | 本书中已经介绍了其中许多模式的例子。下面是一个简单的总结。 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 51 | 52 | 53 | 54 | 58 | 62 | 63 | 64 |
设计模式章节案例
单例2定义可见性
工厂6实现表格工厂
适配器8不使用 gettext() 处理翻译
代理7 48 |

创建一个简单的REST客户端

49 |

创建一个简单的SOAP客户端

50 |
迭代器 55 |

2

56 |

3

57 |
59 |

递归目录迭代器

60 |

使用迭代器

61 |
65 | 66 | 在本章中,我们将研究许多其他设计模式,主要侧重于并发和体系结构模式。 67 | 68 | -------------------------------------------------------------------------------- /mo-kuai-yi/di-shi-yi-zhang-ruan-jian-she-ji-mo-shi-de-shi-xian/chuang-jian-shu-zu-dao-dui-xiang-de-zhuan-hua-qi.md: -------------------------------------------------------------------------------- 1 | # 创建数组到对象的转化器 2 | 3 | Hydrator模式是Data Transfer Object设计模式的一种变体。 它的设计原理非常简单:将数据从一个地方移到另一个地方。 在此,我们将定义类以将数据从数组移动到对象。 4 | 5 | ## 如何做... 6 | 7 | 1.首先,我们定义一个能够使用getters和setters的`Hydrator`类。在这个例子中,我们将使用`Application\Generic\Hydrator\GetSet`。 8 | 9 | ```php 10 | namespace Application\Generic\Hydrator; 11 | class GetSet 12 | { 13 | // code 14 | } 15 | ``` 16 | 17 | 2.接下来,我们定义一个`hydrate()`方法,它同时接受一个数组和一个对象作为参数。然后它调用对象上的`setXXX()`方法来填充数组中的值。我们使用`get_class()`来确定对象的类,然后使用`get_class_methods()`来获取所有方法的列表。 `preg_match()`用于匹配方法的前缀和后缀,后缀被认为是数组的键。 18 | 19 | ```php 20 | public static function hydrate(array $array, $object) 21 | { 22 | $class = get_class($object); 23 | $methodList = get_class_methods($class); 24 | foreach ($methodList as $method) { 25 | preg_match('/^(set)(.*?)$/i', $method, $matches); 26 | $prefix = $matches[1] ?? ''; 27 | $key = $matches[2] ?? ''; 28 | $key = strtolower(substr($key, 0, 1)) . substr($key, 1); 29 | if ($prefix == 'set' && !empty($array[$key])) { 30 | $object->$method($array[$key]); 31 | } 32 | } 33 | return $object; 34 | } 35 | ``` 36 | 37 | ## 如何运行... 38 | 39 | 为了演示如何使用数组到hydrator对象,首先定义`Application\Generic\Hydrator\Hydrator\GetSet`类,如上述。接下来,定义一个可以用来测试概念的实体类。为了这个说明的目的,创建一个`Application\Entity\Person`类,其中包含适当的属性和方法。确保为所有属性定义getter和setter。这里并没有显示所有这样的方法。 40 | 41 | ```php 42 | namespace Application\Entity; 43 | class Person 44 | { 45 | protected $firstName = ''; 46 | protected $lastName = ''; 47 | protected $address = ''; 48 | protected $city = ''; 49 | protected $stateProv = ''; 50 | protected $postalCode = ''; 51 | protected $country = ''; 52 | 53 | public function getFirstName() 54 | { 55 | return $this->firstName; 56 | } 57 | 58 | public function setFirstName($firstName) 59 | { 60 | $this->firstName = $firstName; 61 | } 62 | 63 | // etc. 64 | } 65 | ``` 66 | 67 | 现在可以创建一个名为`chap_11_array_to_object.php`的调用程序,它设置了自动加载,并使用了相应的类。 68 | 69 | ```php 70 | $method(); 32 | } 33 | } 34 | return $array; 35 | } 36 | } 37 | ``` 38 | 39 | {% hint style="info" %} 40 | 请注意,为了方便起见,我们将 `hydrate()` 和 `extract()` 定义为静态方法。 41 | {% endhint %} 42 | 43 | ## 如何运行... 44 | 45 | 定义一个名为`chap_11_object_to_array.php`的调用程序,设置自动加载,并使用相应的类。 46 | 47 | ```php 48 | setFirstName('Li\'lAbner'); 60 | $obj->setLastName('Yokum'); 61 | $obj->setAddress('1DirtStreet'); 62 | $obj->setCity('Dogpatch'); 63 | $obj->setStateProv('Kentucky'); 64 | $obj->setPostalCode('12345'); 65 | $obj->setCountry('USA'); 66 | ``` 67 | 68 | 最后,以静态方式调用 new `extract()`方法。 69 | 70 | ```php 71 | $a = GetSet::extract($obj); 72 | var_dump($a); 73 | ``` 74 | 75 | 输出结果如下截图所示。 76 | 77 | ![](../../.gitbook/assets/image%20%28134%29.png) 78 | 79 | -------------------------------------------------------------------------------- /mo-kuai-yi/di-shi-zhang-gao-ji-suan-fa.md: -------------------------------------------------------------------------------- 1 | # 第十章、高级算法 2 | 3 | 在本章中,我们将介绍: 4 | 5 | * 使用getter和setter 6 | * 实现一个链表 7 | * 建立冒泡排序 8 | * 实现一个堆栈 9 | * 构建一个二进制搜索类 10 | * 实现一个搜索引擎 11 | * 显示多维数组并累计总数 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /mo-kuai-yi/di-shi-zhang-gao-ji-suan-fa/README.md: -------------------------------------------------------------------------------- 1 | # 第十章、高级算法 2 | 3 | 在本章中,我们将介绍: 4 | 5 | * 使用 getter 和 setter 6 | * 实现一个链表 7 | * 建立冒泡排序 8 | * 实现一个堆栈 9 | * 构建一个二分法查找类 10 | * 实现一个搜索引擎 11 | * 显示多维数组并累计总数 12 | 13 | ## 前言 14 | 15 | 在本章中,我们将介绍实现各种高级算法,例如链表、冒泡排序、堆栈和二分法查找。此外,我们还介绍了 getter 和 setter,以及实现搜索引擎和显示来自多维数组的累计总数值。 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /mo-kuai-yi/di-shi-zhang-gao-ji-suan-fa/jian-li-mao-pao-pai-xu.md: -------------------------------------------------------------------------------- 1 | # 建立冒泡排序 2 | 3 | 经典的冒泡排序是经常分配给大学生的练习。尽管如此,掌握这个算法还是很重要的,因为在很多场合,PHP内置的排序函数并不适用。一个例子是对一个多维数组进行排序,而排序键不是第一列。 4 | 5 | 冒泡排序的工作方式是递归迭代列表,并将当前值与下一个值交换。如果你想让项目按升序排列,如果下一个项目小于当前项目,就会发生交换。对于降序,如果相反,则会发生交换。当不再发生交换时,排序就结束了。 6 | 7 | 在下图中,第一次通关后,葡萄和香蕉互换,橙子和樱桃也互换。第2次通过后,葡萄和樱桃被交换。最后一关不再发生交换,冒泡排序结束。 8 | 9 | ![](../../.gitbook/assets/image%20%28128%29.png) 10 | 11 | ## 如何做... 12 | 13 | 1.我们不希望实际移动数组中的值,那样在资源使用方面会非常昂贵。取而代之的是,我们将使用一个链表,这在前面的示例中已经讨论过了。 14 | 15 | ​2. 首先我们使用前面示例中讨论的 `buildLinkedList()` 函数建立一个链表。 16 | 17 | 3. 然后我们定义了一个新的函数 `bubbleSort()`,它通过引用接受链表、主列表、排序字段和一个代表排序顺序(升序或降序)的参数。 18 | 19 | ```php 20 | function bubbleSort(&$linked, $primary, $sortField, $order = 'A') 21 | { 22 | ``` 23 | 24 | 4. 需要的变量包括一个代表迭代次数、交换次数和基于链表的迭代器。 25 | 26 | ```php 27 | static $iterations = 0; 28 | $swaps = 0; 29 | $iterator = new ArrayIterator($linked); 30 | ``` 31 | 32 | 5. 在 `while()` 循环中,我们只有在迭代仍然有效的情况下才会继续,也就是说仍然在进行中。然后我们获得当前的键和值,以及下一个键和值。请注意额外的`if()`语句,以确保迭代仍然有效(也就是说,确保我们不会从列表末尾掉下来!)。 33 | 34 | ```php 35 | while ($iterator->valid()) { 36 | $currentLink = $iterator->current(); 37 | $currentKey = $iterator->key(); 38 | if (!$iterator->valid()) break; 39 | $iterator->next(); 40 | $nextLink = $iterator->current(); 41 | $nextKey = $iterator->key(); 42 | ``` 43 | 44 | 6. 接下来我们检查排序是升序还是降序。根据方向的不同,我们检查下一个值是否大于或小于当前值。比较的结果存储在 `$expr` 中。 45 | 46 | ```php 47 | if ($order == 'A') { 48 | $expr = $primary[$linked->offsetGet 49 | ($currentKey)][$sortField] > 50 | $primary[$linked->offsetGet($nextKey)][$sortField]; 51 | } else { 52 | $expr = $primary[$linked->offsetGet 53 | ($currentKey)][$sortField] < 54 | $primary[$linked->offsetGet($nextKey)][$sortField]; 55 | } 56 | ``` 57 | 58 | 7. 如果`$expr` 的值为`TRUE`,并且我们有有效的当前键和下一个键,那么这些值就会在链表中进行交换。我们也会对 `$swaps` 进行增量。 59 | 60 | ```php 61 | if ($expr && $currentKey && $nextKey 62 | && $linked->offsetExists($currentKey) 63 | && $linked->offsetExists($nextKey)) { 64 | $tmp = $linked->offsetGet($currentKey); 65 | $linked->offsetSet($currentKey, 66 | $linked->offsetGet($nextKey)); 67 | $linked->offsetSet($nextKey, $tmp); 68 | $swaps++; 69 | } 70 | } 71 | ``` 72 | 73 | 8. 最后,如果发生了任何交换,我们需要再次进行迭代,直到不再有交换。据此,我们对同一方法进行递归调用。 74 | 75 | ```php 76 | if ($swaps) bubbleSort($linked, $primary, $sortField, $order); 77 | ``` 78 | 79 | 9. 真正的返回值是重新组织的链表。我们还返回迭代次数,只是为了参考。 80 | 81 | ```php 82 | return ++$iterations; 83 | } 84 | ``` 85 | 86 | ## 如何运行... 87 | 88 | 将前面讨论过的 `bubbleSort()` 函数添加到前面的示例中创建的 `include` 文件中。你可以使用前面的示例中讨论的相同逻辑来读取 `customer.csv` 文件,生成一个主列表。 89 | 90 | ```php 91 | stack = new SplStack(); 27 | } 28 | ``` 29 | 30 | 3. 之后我们定义了从堆栈中添加和删除的方法,即经典的 `push()` 和 `pop()` 方法。 31 | 32 | ```php 33 | public function push($message) 34 | { 35 | $this->stack->push($message); 36 | } 37 | public function pop() 38 | { 39 | return $this->stack->pop(); 40 | } 41 | ``` 42 | 43 | 4. 我们还抛出了一个`__invoke()`的实现,它可以返回栈属性的实例。这允许我们在直接函数调用中使用对象。 44 | 45 | ```php 46 | public function __invoke() 47 | { 48 | return $this->stack; 49 | } 50 | ``` 51 | 52 | ## 如何运行... 53 | 54 | 堆栈的一个可能用途是存储消息。在消息的情况下,通常希望先检索最新的消息,因此这是堆栈的一个完美用例。如本示例中所讨论的那样,定义 `Application\Generic\Stack` 类。接下来,定义一个调用程序,设置自动加载并创建一个栈的实例。 55 | 56 | ```php 57 | push('1st Message: ' . date('H:i:s')); 70 | sleep(3); 71 | 72 | echo 'Do Something Else ... ' . PHP_EOL; 73 | $stack->push('2nd Message: ' . date('H:i:s')); 74 | sleep(3); 75 | 76 | echo 'Do Something Else Again ... ' . PHP_EOL; 77 | $stack->push('3rd Message: ' . date('H:i:s')); 78 | sleep(3); 79 | ``` 80 | 81 | 最后,简单地在堆栈中迭代以检索消息。注意,你可以像调用函数一样调用栈对象,它将返回 `SplStack` 实例。 82 | 83 | ```php 84 | echo 'What Time Is It?' . PHP_EOL; 85 | foreach ($stack() as $item) { 86 | echo $item . PHP_EOL; 87 | } 88 | ``` 89 | 90 | 下面是预期的输出。 91 | 92 | ![](../../.gitbook/assets/image%20%28131%29.png) 93 | 94 | -------------------------------------------------------------------------------- /mo-kuai-yi/di-si-zhang-shi-yong-php-mian-xiang-dui-xiang-cheng-xu-she-ji.md: -------------------------------------------------------------------------------- 1 | # 第四章、使用 PHP 面向对象程序设计 2 | 3 | -------------------------------------------------------------------------------- /mo-kuai-yi/di-si-zhang-shi-yong-php-mian-xiang-dui-xiang-cheng-xu-she-ji/README.md: -------------------------------------------------------------------------------- 1 | # 第四章、使用 PHP 面向对象程序设计 2 | 3 | 在本章节我们将讨论: 4 | 5 | * 类的开发 6 | * 类的扩展 7 | * 使用静态属性和方法 8 | * 使用命名空间 9 | * 定义可见性 10 | * 使用接口 11 | * 使用特性 12 | * 实现匿名类 13 | 14 | 在本章中,我们将考虑利用 PHP 7.0、7.1 和更高版本中可用的**面向对象编程**(**OOP**)功能。 PHP 7.x 中可用的大多数 OOP 功能在 PHP 5.6 中也可用。 PHP 7 中引入的新功能是对**匿名类**的支持。 在 PHP 7.1 中,您可以修改类常量的可见性。 15 | 16 | {% hint style="info" %} 17 | 另一个全新的功能是捕捉某些类型的错误。在第13章,最佳实践、测试和调试中会有更详细的讨论。 18 | {% endhint %} 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /mo-kuai-yi/di-si-zhang-shi-yong-php-mian-xiang-dui-xiang-cheng-xu-she-ji/ding-yi-ke-jian-xing.md: -------------------------------------------------------------------------------- 1 | # 定义可见性 2 | 3 | 可以理解,可见性一词与应用程序安全性无关! 相反,它只是一种控制代码使用的机制。 它可以用来引导没有经验的开发人员远离只能在类定义内部调用的方法的公共使用。 4 | 5 | ## 如何做... 6 | 7 | 1.通过在任何属性或方法定义之前添加 `public`,`protected`或`private`关键字来指示可见性级别。 您可以将属性标记为受保护或私有,以强制只通过公共的`getter`和`setter`进行访问。 8 | 9 | 2.在这个例子中,定义了一个`Base`类,它有一个受保护的属性`$id`,为了访问这个属性,定义了`getId()`和`setId()`两个公共方法。受保护的方法`generateRandId()`可以在内部使用,并且在`Customer`子类中被继承。这个方法不能在类定义之外直接调用。注意使用新的PHP 7 `random_bytes()`函数来创建一个随机ID。 10 | 11 | ```php 12 | class Base 13 | { 14 | protected $id; 15 | private $key = 12345; 16 | public function getId() 17 | { 18 | return $this->id; 19 | } 20 | public function setId() 21 | { 22 | $this->id = $this->generateRandId(); 23 | } 24 | protected function generateRandId() 25 | { 26 | return unpack('H*', random_bytes(8))[1]; 27 | } 28 | } 29 | 30 | class Customer extends Base 31 | { 32 | protected $name; 33 | public function getName() 34 | { 35 | return $this->name; 36 | } 37 | public function setName($name) 38 | { 39 | $this->name = $name; 40 | } 41 | } 42 | ``` 43 | 44 | {% hint style="warning" %} 45 | **最佳实践** 46 | 47 | 将属性标记为受保护,并定义公共的 ****getNameOfProperty\(\) 和 setNameOfProperty\(\) 方法来控制对属性的访问。这种方法被称为 `getters` 和 `setters`。 48 | {% endhint %} 49 | 50 | 3.将一个属性或方法标记为私有,以防止它被继承或在类定义之外可见。这是将类创建为**单例**的好方法。 51 | 52 | 4.下一个代码示例显示了一个类 `Registry`,它只能有一个实例。因为构造函数被标记为私有,所以只有通过静态方法 `getInstance()`才能创建实例: 53 | 54 | ```php 55 | class Registry 56 | { 57 | protected static $instance = NULL; 58 | protected $registry = array(); 59 | private function __construct() 60 | { 61 | // 没有人可以创建这个类的实例 62 | } 63 | public static function getInstance() 64 | { 65 | if (!self::$instance) { 66 | self::$instance = new self(); 67 | } 68 | return self::$instance; 69 | } 70 | public function __get($key) 71 | { 72 | return $this->registry[$key] ?? NULL; 73 | } 74 | public function __set($key, $value) 75 | { 76 | $this->registry[$key] = $value; 77 | } 78 | } 79 | 80 | ``` 81 | 82 | {% hint style="info" %} 83 | 您可以将方法标记为 `final`,以防止其被覆盖。将一个类标记为 `final`,以防止它被扩展。 84 | {% endhint %} 85 | 86 | 5.通常情况下,类常量的可见性级别为 `public`,而在 PHP 7.1 中,可以将类常量声明为 `protected`或`private`。在下面的例子中,`TEST_WHOLE_WORLD` 类常量的行为与 PHP 5 中的完全相同。 接下来的两个常量,`TEST_INHERITED` 和 `TEST_LOCAL`,遵循与任何受保护或私有属性或方法相同的规则: 87 | 88 | ```php 89 | class Test 90 | { 91 | 92 | public const TEST_WHOLE_WORLD = 'visible.everywhere'; 93 | 94 | // NOTE: 只能在 PHP 7.1及以上版本中工作 95 | protected const TEST_INHERITED = 'visible.in.child.classes'; 96 | 97 | // NOTE: 只能在 PHP 7.1及以上版本中工作 98 | private const TEST_LOCAL= 'local.to.class.Test.only'; 99 | 100 | public static function getTestInherited() 101 | { 102 | return static::TEST_INHERITED; 103 | } 104 | 105 | public static function getTestLocal() 106 | { 107 | return static::TEST_LOCAL; 108 | } 109 | 110 | } 111 | ``` 112 | 113 | ## 如何运行... 114 | 115 | 创建文件`chap_04_basic_visibility.php`并定义两个类:`Base`和`Customer`。 接下来,编写代码以创建每个实例: 116 | 117 | ```php 118 | $base = new Base(); 119 | $customer = new Customer(); 120 | ``` 121 | 122 | 请注意,下面的代码工作正常,事实上被认为是最佳实践: 123 | 124 | ```php 125 | $customer->setId(); 126 | $customer->setName('Test'); 127 | echo 'Welcome ' . $customer->getName() . PHP_EOL; 128 | echo 'Your new ID number is: ' . $customer->getId() . PHP_EOL; 129 | ``` 130 | 131 | 尽管 `$id` 是受保护的,但相应的方法 `getId()` 和 `setId()` 都是公共的,因此可以从类定义之外访问。下面是输出结果: 132 | 133 | ![](../../.gitbook/assets/image%20%2842%29.png) 134 | 135 | 然而,下面的代码行将无法工作,因为私有和受保护的属性无法从类定义之外访问: 136 | 137 | ```php 138 | echo 'Key (does not work): ' . $base->key; 139 | echo 'Key (does not work): ' . $customer->key; 140 | echo 'Name (does not work): ' . $customer->name; 141 | echo 'Random ID (does not work): ' . $customer->generateRandId(); 142 | ``` 143 | 144 | 下面的输出显示了预期的错误: 145 | 146 | ![](../../.gitbook/assets/image%20%2853%29.png) 147 | 148 | ## 参考 149 | 150 | 有关 `getter` 和 `setter` 的更多信息,请参阅第十章标题为《使用 `getter` 和 `setter` 》的章节。有关PHP 7.1类常量可见性设置的更多信息,请参见[https://wiki.php.net/rfc/class\_const\_visibility](https://wiki.php.net/rfc/class_const_visibility)。 151 | 152 | -------------------------------------------------------------------------------- /mo-kuai-yi/di-si-zhang-shi-yong-php-mian-xiang-dui-xiang-cheng-xu-she-ji/shi-yong-jing-tai-shu-xing-he-fang-fa.md: -------------------------------------------------------------------------------- 1 | # 使用静态属性和方法 2 | 3 | PHP 让你无需创建一个类的实例就可以访问属性或方法。为此使用的关键字是 `static`。 4 | 5 | ## 如何做... 6 | 7 | 1.最简单的是,在声明一个普通属性或方法时,只需在声明可见性级别后添加 `static` 关键字。使用 `self`关键字在内部引用该属性: 8 | 9 | ```php 10 | class Test 11 | { 12 | public static $test = 'TEST'; 13 | public static function getTest() 14 | { 15 | return self::$test; 16 | } 17 | } 18 | ``` 19 | 20 | 2. `self` 关键字会提前绑定,在访问子类的静态信息时会出现问题。如果一定需要访问子类中的信息,请使用 `static` 关键字来代替 `self` 。这个过程被称为**后期静态绑定**(**Late Static Binding**)。 21 | 22 | 3.在下面的例子中,如果运行 `Child::getEarlyTest()` ,输出将是 **TEST**。另一方面,如果运行 `Child::getLateTest()` ,输出将是 **CHILD**。原因是 PHP 在使用 `self` 时,会绑定最早的定义,而静态关键字则使用最新的绑定: 23 | 24 | ```php 25 | class Test2 26 | { 27 | public static $test = 'TEST2'; 28 | public static function getEarlyTest() 29 | { 30 | return self::$test; 31 | } 32 | public static function getLateTest() 33 | { 34 | return static::$test; 35 | } 36 | } 37 | 38 | class Child extends Test2 39 | { 40 | public static $test = 'CHILD'; 41 | } 42 | ``` 43 | 44 | 4.在许多情况下,工厂设计模式与静态方法一起使用,以产生给定不同参数的对象实例。在这个例子中,定义了一个静态方法 `factory()`,它返回一个 PDO 连接: 45 | 46 | ```php 47 | public static function factory( 48 | $driver,$dbname,$host,$user,$pwd,array $options = []) 49 | { 50 | $dsn = sprintf('%s:dbname=%s;host=%s', 51 | $driver, $dbname, $host); 52 | try { 53 | return new PDO($dsn, $user, $pwd, $options); 54 | } catch (PDOException $e) { 55 | error_log($e->getMessage); 56 | } 57 | } 58 | ``` 59 | 60 | ## 如何运行... 61 | 62 | 你可以使用类解析运算符 **“::“** 来引用静态属性和方法。给定前面所示的 `Test` 类,如果运行这段代码: 63 | 64 | ```php 65 | echo Test::$test; 66 | echo PHP_EOL; 67 | echo Test::getTest(); 68 | echo PHP_EOL; 69 | ``` 70 | 71 | 你会看到这样的输出: 72 | 73 | ![](../../.gitbook/assets/image%20%2850%29.png) 74 | 75 | 为了说明后期静态绑定,基于前面显示的类 `Test2` 和 `Child` ,请尝试以下代码: 76 | 77 | ```php 78 | echo Test2::$test; 79 | echo Child::$test; 80 | echo Child::getEarlyTest(); 81 | echo Child::getLateTest(); 82 | ``` 83 | 84 | 输出说明了 `self` 和 `static` 的区别: 85 | 86 | ![](../../.gitbook/assets/image%20%2856%29.png) 87 | 88 | 最后,要测试前面显示的 `factory()` 方法,请将代码保存到 `Application\Database` 文件夹中`Connection.php` 文件的 `Application\Database\Connection` 类中。 然后,您可以尝试以下操作: 89 | 90 | ```php 91 | include __DIR__ . '/../Application/Database/Connection.php'; 92 | use Application\Database\Connection; 93 | $connection = Connection::factory( 94 | 'mysql', 'php7cookbook', 'localhost', 'test', 'password'); 95 | $stmt = $connection->query('SELECT name FROM iso_country_codes'); 96 | while ($country = $stmt->fetch(PDO::FETCH_COLUMN)) 97 | echo $country . ''; 98 | ``` 99 | 100 | 您将看到从示例数据库中提取的国家/地区列表: 101 | 102 | ![](../../.gitbook/assets/image%20%2846%29.png) 103 | 104 | ## 参考... 105 | 106 | 关于后期静态绑定的更多信息,请参见PHP文档中的解释。 107 | 108 | [http://php.net/manual/en/language.oop5.late-static-bindings.php](http://php.net/manual/en/language.oop5.late-static-bindings.php) 109 | 110 | -------------------------------------------------------------------------------- /mo-kuai-yi/di-wu-zhang-yu-shu-ju-ku-de-jiao-hu.md: -------------------------------------------------------------------------------- 1 | # 第五章、与数据库的交互 2 | 3 | 在本章中,我们将介绍以下主题: 4 | 5 | * 使用PDO连接到数据库 6 | * 构建一个OOP SQL查询构建器 7 | * 处理分页 8 | * 定义实体以匹配数据库表 9 | * 将实体类与RDBMS查询绑定 10 | * 将二次查找嵌入到查询结果中 11 | * 实现jQuery DataTables的PHP查找 12 | 13 | ## 引言 14 | 15 | 在这一章中,我们将介绍一系列利用PHP数据对象(PDO)扩展的数据库连接方法。常见的编程问题都将得到解决,如结构化查询语言\(SQL\)的生成、分页和将对象与数据库表绑定。最后,我们将介绍以嵌入式匿名函数的形式处理二次查找,以及为 jQuery DataTables 创建 AJAX 请求 。 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /mo-kuai-yi/di-wu-zhang-yu-shu-ju-ku-de-jiao-hu/README.md: -------------------------------------------------------------------------------- 1 | # 第五章、与数据库的交互 2 | 3 | 在本章中,我们将介绍以下主题: 4 | 5 | * 使用PDO连接数据库 6 | * 构建一个OOP SQL 查询生成器 7 | * 处理分页 8 | * 定义实体以匹配数据库表 9 | * 将实体类与RDBMS查询绑定 10 | * 将二次查找嵌入到查询结果中 11 | * 实现jQuery DataTables的PHP查找 12 | 13 | ## 引言 14 | 15 | 在这一章中,我们将介绍一系列利用PHP数据对象(PDO)扩展的数据库连接方法。常见的编程问题都将得到解决,如结构化查询语言\(SQL\)的生成、分页和将对象与数据库表绑定。最后,我们将介绍以嵌入式匿名函数的形式处理二次查找,以及为 jQuery DataTables 创建 AJAX 请求 。 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /mo-kuai-yi/di-wu-zhang-yu-shu-ju-ku-de-jiao-hu/gou-jian-yi-ge-oop-sql-cha-xun-sheng-cheng-qi.md: -------------------------------------------------------------------------------- 1 | # 构建一个 OOP SQL 查询生成器 2 | 3 | PHP 7实现了一种称为上下文相关的词法分析器。这意味着,如果上下文允许,通常保留的词可以被使用,因此,当构建面向对象的 SQL 构建器时,我们可以使用名为 `and`, `or`, `not` 等方法。 4 | 5 | ## 如何做... 6 | 7 | 1.我们定义了一个 `Application/Database/Finder` 类。在这个类中,我们定义了与我们最喜欢的SQL操作相匹配的方法。 8 | 9 | ```php 10 | namespace Application\Database; 11 | class Finder 12 | { 13 | public static $sql = ''; 14 | public static $instance = NULL; 15 | public static $prefix = ''; 16 | public static $where = array(); 17 | public static $control = ['', '']; 18 | 19 | // $a == name of table 20 | // $cols = column names 21 | public static function select($a, $cols = NULL) 22 | { 23 | self::$instance = new Finder(); 24 | if ($cols) { 25 | self::$prefix = 'SELECT ' . $cols . ' FROM ' . $a; 26 | } else { 27 | self::$prefix = 'SELECT * FROM ' . $a; 28 | } 29 | return self::$instance; 30 | } 31 | 32 | public static function where($a = NULL) 33 | { 34 | self::$where[0] = ' WHERE ' . $a; 35 | return self::$instance; 36 | } 37 | 38 | public static function like($a, $b) 39 | { 40 | self::$where[] = trim($a . ' LIKE ' . $b); 41 | return self::$instance; 42 | } 43 | 44 | public static function and($a = NULL) 45 | { 46 | self::$where[] = trim('AND ' . $a); 47 | return self::$instance; 48 | } 49 | 50 | public static function or($a = NULL) 51 | { 52 | self::$where[] = trim('OR ' . $a); 53 | return self::$instance; 54 | } 55 | 56 | public static function in(array $a) 57 | { 58 | self::$where[] = 'IN ( ' . implode(',', $a) . ' )'; 59 | return self::$instance; 60 | } 61 | 62 | public static function not($a = NULL) 63 | { 64 | self::$where[] = trim('NOT ' . $a); 65 | return self::$instance; 66 | } 67 | 68 | public static function limit($limit) 69 | { 70 | self::$control[0] = 'LIMIT ' . $limit; 71 | return self::$instance; 72 | } 73 | 74 | public static function offset($offset) 75 | { 76 | self::$control[1] = 'OFFSET ' . $offset; 77 | return self::$instance; 78 | } 79 | 80 | public static function getSql() 81 | { 82 | self::$sql = self::$prefix 83 | . implode(' ', self::$where) 84 | . ' ' 85 | . self::$control[0] 86 | . ' ' 87 | . self::$control[1]; 88 | preg_replace('/ /', ' ', self::$sql); 89 | return trim(self::$sql); 90 | } 91 | } 92 | 93 | ``` 94 | 95 | 2.每个用于生成SQL片段的函数都会返回相同的属性,即 `$instance`。这使得我们可以使用一个流畅的接口来表示代码,比如这样。 96 | 97 | ```php 98 | $sql = Finder::select('project')->where('priority > 9') ... etc. 99 | ``` 100 | 101 | ## 如何运行... 102 | 103 | 将前面定义的代码复制到 `Application/Database` 文件夹下的`Finder.php`文件中。然后您可以创建一个`chap_05_oop_query_builder.php`调用程序,它初始化了在第一章建立基础中定义的自动加载器。然后你可以运行`Finder::select()`来生成一个对象,从这个对象中可以呈现SQL字符串。 104 | 105 | ```php 106 | where() 113 | ->like('name', '%secret%') 114 | ->and('priority > 9') 115 | ->or('code')->in(['4', '5', '7']) 116 | ->and()->not('created_at') 117 | ->limit(10) 118 | ->offset(20); 119 | 120 | echo Finder::getSql(); 121 | ``` 122 | 123 | 这是预编码的结果: 124 | 125 | ![](../../.gitbook/assets/image%20%2878%29.png) 126 | 127 | ## 参考 128 | 129 | 有关上下文相关词法分析器的更多信息,请参见本文: 130 | 131 | [https://wiki.php.net/rfc/context\_sensitive\_lexer](https://wiki.php.net/rfc/context_sensitive_lexer) 132 | 133 | -------------------------------------------------------------------------------- /mo-kuai-yi/di-yi-zhang-jian-li-ji-chu/README.md: -------------------------------------------------------------------------------- 1 | # 第一章、建立基础 2 | 3 | 在这一章中,我们将讨论以下主题: 4 | 5 | * PHP 7 安装注意事项 6 | * 使用内置的 PHP web 服务器 7 | * 创建一个 MySQL 测试 数据库 8 | * 安装 PHPUnit 9 | * 实现类的自动加载 10 | * 抓取一个网站 11 | * 建立一个深度网络扫描器 12 | * 创建一个 PHP 5 到 PHP 7 的代码转换器 13 | 14 | ## 引言 15 | 16 | 这一章是快速入门,它将帮助您启动并运行 PHP 7,这样你就可以马上开始实现这些示例了。本书的基本假设是您已经对 PHP 和编程有了很好的了解。虽然本书不会详细介绍 PHP 的实际安装,但是鉴于 PHP 7相对较新,我们将尽最大努力指出 PHP 7安装过程中可能遇到的问题。 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /mo-kuai-yi/di-yi-zhang-jian-li-ji-chu/an-zhuang-phpunit.md: -------------------------------------------------------------------------------- 1 | # 安装 PHPUnit 2 | 3 | 单元测试可以说是测试PHP代码最流行的手段。大多数开发人员都会同意,一套可靠的测试是任何正确开发项目的要求。但很少有开发人员真正编写这些测试。少数幸运的开发者有一个独立的测试小组为他们编写测试。然而,经过几个月与测试组的小冲突后,少数幸运儿往往会开始抱怨和抗议。无论如何,任何一本关于 PHP 的书,如果只字不提测试,那将是不完整的。 4 | 5 | 找到 PHPUnit 最新版本的地方是[https://phpunit.de/](https://phpunit.de/)。PHPUnit5.1 及以上版本支持PHP7。点击所需版本的链接,你将下载一个 phpunit.phar 文件。然后你可以使用存档文件执行命令,如下所示: 6 | 7 | ```bash 8 | php phpunit.phar 9 | ``` 10 | 11 | > **小贴士** 12 | > 13 | > `phar` 命令是 `PHP Archive` 的缩写。该技术基于`tar`,而 `tar` 本身已在 UNIX 中使用。`phar` 文件是一个 PHP 文件的集合,为了方便起见,这些文件被打包成一个文件。 14 | 15 | -------------------------------------------------------------------------------- /mo-kuai-yi/di-yi-zhang-jian-li-ji-chu/ding-yi-mysql-ce-shi-shu-ju-ku.md: -------------------------------------------------------------------------------- 1 | # 创建一个 MySQL 测试数据库 2 | 3 | 为了测试目的,我们在本书的源代码中提供了一个 SQL 文件,其中包含了 [https://github.com/dbierer/php7cookbook](https://github.com/dbierer/php7cookbook) 的示例数据。这本书的示例中使用的数据库的名称是 php7cookbook。 4 | 5 | ## 怎么做... 6 | 7 | 1.定义一个MySQL数据库 php7cookbook。同时将新数据库的权限分配给一个名为 cook 的用户,密码为book。下表总结了这些设置。 8 | 9 | | 项目 | 注释 | 10 | | :--- | :--- | 11 | | 数据库名称 | `php7cookbook` | 12 | | 数据库用户 | `cook` | 13 | | 数据库用户密码 | `book` | 14 | 15 | 2.这是创建数据库所需的SQL示例: 16 | 17 | ```sql 18 | CREATE DATABASE IF NOT EXISTS dbname DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci; 19 | CREATE USER 'user'@'%' IDENTIFIED WITH mysql_native_password; 20 | SET PASSWORD FOR 'user'@'%' = PASSWORD('userPassword'); 21 | GRANT ALL PRIVILEGES ON dbname.* to 'user'@'%'; 22 | GRANT ALL PRIVILEGES ON dbname.* to 'user'@'localhost'; 23 | FLUSH PRIVILEGES; 24 | ``` 25 | 26 | 3.将样本值导入到新数据库中。 导入文件`php7cookbook.sql`位于[https://github.com/dbierer/php7cookbook/blob/master/php7cookbook.sql](https://github.com/dbierer/php7cookbook/blob/master/php7cookbook.sql)。 27 | 28 | -------------------------------------------------------------------------------- /mo-kuai-yi/di-yi-zhang-jian-li-ji-chu/jian-li-yi-ge-shen-du-wang-luo-sao-miao-qi.md: -------------------------------------------------------------------------------- 1 | # 建立一个深度网络扫描器 2 | 3 | 有时您需要扫描一个网站,但是要更深一层。例如,你想建立一个网站的网络树图。这可以通过寻找所有 `` 标签,并跟随 `HREF` 属性到下一个网页来实现。一旦你获得了子页面,你就可以继续扫描,以便完成树状图。 4 | 5 | ## 如何做... 6 | 7 | 1.如前所述,深度网络扫描器的核心组件是基本的 `Hoover` 类。本示例中介绍的基本过程是扫描目标网站并收集所有 `HREF` 属性。为此,我们定义了 `Application\Web\Deep` 类。 我们添加一个代表 DNS 域的属性: 8 | 9 | ```php 10 | namespace Application\Web; 11 | class Deep 12 | { 13 | protected $domain; 14 | ``` 15 | 16 | 2.接下来,我们定义了一个方法,该方法将对扫描列表中代表的每个网站的标签进行抓取。为了防止扫描器搜索整个**万维网**(**WWW**),我们将扫描范围限制在目标域。之所以加入了`yield from` ,是因为我们需要输出由 `Hoover::getTags()` 产生的整个数组。`yield from` 语法允许我们将数组视为一个子生成器: 17 | 18 | ```php 19 | public function scan($url, $tag) 20 | { 21 | $vac = new Hoover(); 22 | $scan = $vac->getAttribute($url, 'href', 23 | $this->getDomain($url)); 24 | $result = array(); 25 | foreach ($scan as $subSite) { 26 | yield from $vac->getTags($subSite, $tag); 27 | } 28 | return count($scan); 29 | } 30 | ``` 31 | 32 | {% hint style="info" %} 33 | 使用 `yield from` 可以将 `scan()` 方法变成一个PHP 7的委托生成器。通常情况下,你会倾向于将扫描的结果存储到一个数组中。问题是,在这种情况下,检索到的信息量可能是巨大的。因此,为了节省内存和立即产生结果,最好的方式是使用 `yield`。否则,就会有一个漫长的等待,这很可能会出现内存不足的错误。 34 | {% endhint %} 35 | 36 | 3.为了保持在同一个域内,我们需要一个方法来从URL中返回域。我们使用方便的 `parse_url()` 函数来实现这一目的: 37 | 38 | ```php 39 | public function getDomain($url) 40 | { 41 | if (!$this->domain) { 42 | $this->domain = parse_url($url, PHP_URL_HOST); 43 | } 44 | return $this->domain; 45 | } 46 | ``` 47 | 48 | ## 如何运行... 49 | 50 | 首先,先去定义前面定义的 `Application\Web\Deep` 类,以及前面配方中定义的 `Application\Web\Hoover` 类。 51 | 52 | 接下来,在 `chap_01_deep_scan_website.php`中定义一个代码块来设置自动加载\(如本章前面所述\): 53 | 54 | ```php 55 | scan($url, $tag) as $item) { 81 | $src = $item['attributes']['src'] ?? NULL; 82 | if ($src && (stripos($src, 'png') || stripos($src, 'jpg'))) { 83 | printf('
', $src); 84 | } 85 | } 86 | ``` 87 | 88 | ## 参考 89 | 90 | 关于生成器和`yield from`的更多信息,请参阅 [http://php.net/manual/en/language.generators.syntax.php](http://php.net/manual/en/language.generators.syntax.php) 91 | 92 | -------------------------------------------------------------------------------- /mo-kuai-yi/di-yi-zhang-jian-li-ji-chu/shi-yong-nei-zhi-de-php-web-fu-wu-qi.md: -------------------------------------------------------------------------------- 1 | # 使用内置的 PHP web 服务器 2 | 3 | 除了单元测试和直接从命令行运行 PHP 之外,显而易见的测试应用程序的方法是使用 web 服务器。对于长期项目,为 web 服务器开发一个虚拟主机定义是非常有益的,它最接近于客户使用的虚拟主机定义。为各种 web 服务器(即 Apache、 NGINX 等)创建这样的定义超出了本书的范围。另一个快速、易于使用的替代方案(我们在这里有空间讨论的)是使用内置的 PHP 7 web 服务器。 4 | 5 | ## 怎么做... 6 | 7 | 1.要激活 PHP web 服务器,首先要改变当前所在目录,进入到您的代码文件夹。 8 | 9 | 2.然后你需要提供主机名或IP地址,以及可选的端口。下面是一个例子,你可以用它来运行本书提供的示例。 10 | 11 | ```bash 12 | cd /path/to/recipes 13 | php -S localhost:8080 14 | ``` 15 | 16 | 您将在屏幕上看到如下所示的输出: 17 | 18 | ![](../../.gitbook/assets/image%20%283%29.png) 19 | 20 | 3.随着内置 Web 服务器继续为请求提供服务,您还将看到访问信息,HTTP状态代码和请求信息。 21 | 22 | 4.如果需要将 Web 服务器文档根目录设置为当前目录以外的目录,则可以使用 **-t** 标志。 该标志之后必须跟随有效的目录路径。 内置的 Web 服务器会将这个目录视为 Web 文档的根目录,出于安全原因,这很有用。 出于安全原因,某些框架(例如Zend Framework)要求Web文档根目录与实际源代码所在的位置不同。 23 | 24 | 这是使用 **-t** 标志的示例: 25 | 26 | ```bash 27 | php -S localhost:8080 -t source/chapter01 28 | ``` 29 | 30 | 这是示例的输出: 31 | 32 | ![](../../.gitbook/assets/image%20%285%29.png) 33 | 34 | -------------------------------------------------------------------------------- /mo-kuai-yi/di-yi-zhang-jian-li-ji-chu/zhua-qu-yi-ge-wang-zhan.md: -------------------------------------------------------------------------------- 1 | # 抓取一个网站 2 | 3 | 很多时候,抓取一个网站并从特定的标签中提取信息是非常有价值的。这种基本的机制可以用来在网络上搜索有价值的信息。在其他时候,你可能需要得到一个 `` 标签和 `SRC` 属性的列表,或者 `
` 标签和相应的 `HREF` 属性。这种可能性是无穷无尽的。 4 | 5 | ## 如何做... 6 | 7 | 1.首先,我们需要抓取目标网站的内容。乍一看,似乎我们应该发出 cURL 请求,或者干脆使用 `file_get_contents()` 。这些方法的问题是,我们最终将不得不进行大量的字符串操作,很可能不得不过度使用可怕的正则表达式。为了避免这一切,我们将简单地利用已经存在的 PHP 7 类 `DOMDocument` 。所以我们创建一个 `DOMDocument` 实例,并将其设置为**UTF-8**。我们不关心空格,使用方便的 `loadHTMLFile()` 方法将网站的内容加载到对象中: 8 | 9 | ```php 10 | public function getContent($url) 11 | { 12 | if (!$this->content) { 13 | if (stripos($url, 'http') !== 0) { 14 | $url = 'http://' . $url; 15 | } 16 | $this->content = new DOMDocument('1.0', 'utf-8'); 17 | $this->content->preserveWhiteSpace = FALSE; 18 | // @ used to suppress warnings generated from // improperly configured web pages 19 | @$this->content->loadHTMLFile($url); 20 | } 21 | return $this->content; 22 | } 23 | ``` 24 | 25 | {% hint style="info" %} 26 | 请注意,我们在调用 `loadHTMLFile()` 方法之前加上了 `@`。这并不是为了掩盖错误的编码`(!)`,就像在PHP 5中经常发生的那样!而是当解析器遇到写得不好的HTML时,`@` 会抑制产生的通知。相反,当解析器遇到写得不好的HTML时,`@` 会抑制产生的通知。大概我们可以捕获这些通知并记录下来,可能会给我们的 `Hoover` 类提供一个诊断功能。 27 | {% endhint %} 28 | 29 | 2.接下来,我们需要提取感兴趣的标签。我们使用 `getElementsByTagName()` 方法来实现这一目的。如果我们希望提取所有标记,我们可以提供 `*` 作为参数: 30 | 31 | ```php 32 | public function getTags($url, $tag) 33 | { 34 | $count = 0; 35 | $result = array(); 36 | $elements = $this->getContent($url) 37 | ->getElementsByTagName($tag); 38 | foreach ($elements as $node) { 39 | $result[$count]['value'] = trim(preg_replace('/\s+/', ' ', $node->nodeValue)); 40 | if ($node->hasAttributes()) { 41 | foreach ($node->attributes as $name => $attr) 42 | { 43 | $result[$count]['attributes'][$name] = 44 | $attr->value; 45 | } 46 | } 47 | $count++; 48 | } 49 | return $result; 50 | } 51 | ``` 52 | 53 | 3.提取某些属性而不是标签也可能是有意义的。因此,我们为此定义了另一个方法。在这种情况下,我们需要解析所有的标签并使用 `getAttribute()` 。你会注意到,有一个DNS域的参数。我们添加这个参数是为了使扫描保持在同一个域内(例如,如果你正在构建一个网络树): 54 | 55 | ```php 56 | public function getAttribute($url, $attr, $domain = NULL) 57 | { 58 | $result = array(); 59 | $elements = $this->getContent($url) 60 | ->getElementsByTagName('*'); 61 | foreach ($elements as $node) { 62 | if ($node->hasAttribute($attr)) { 63 | $value = $node->getAttribute($attr); 64 | if ($domain) { 65 | if (stripos($value, $domain) !== FALSE) { 66 | $result[] = trim($value); 67 | } 68 | } else { 69 | $result[] = trim($value); 70 | } 71 | } 72 | } 73 | return $result; 74 | } 75 | ``` 76 | 77 | ## 如何运行... 78 | 79 | 为了使用新的 `Hoover` 类,请初始化自动加载器(如前所述)并创建 `Hoover` 类的实例。 然后,您可以运行 `Hoover::getTags()` 方法,从指定为参数的URL生成标签数组。 80 | 81 | 下面是 `chap_01_vacuuming_website.php` 中的一段代码,它使用 `Hoover` 类来扫描O'Reilly网站的 `` 标签: 82 | 83 | ```php 84 | getTags($url, $tag)); 101 | ``` 102 | 103 | 输出结果如下所示: 104 | 105 | ![](../../.gitbook/assets/image%20%286%29.png) 106 | 107 | ## 参考 108 | 109 | 更多关于 DOM 的信息,请参阅 PHP 参考 [http://php.net/manual/en/class.domdocument.php](http://php.net/manual/en/class.domdocument.php)。 110 | 111 | --------------------------------------------------------------------------------