├── .gitignore ├── 19level.md ├── ElasticSearch简明教程.md ├── LICENSE ├── LeetCode.md ├── Mac新环境搭建.md ├── PHPStorm+Xdebug.md ├── README.md ├── accounts.json ├── composer.json ├── composer.lock ├── dev.sh ├── docker.md ├── elasticSearch.md ├── git.md ├── helper.php ├── html+css.md ├── http.md ├── javascript.md ├── js ├── html │ ├── flow.html │ ├── form.html │ ├── layer.html │ ├── menu.html │ ├── nav.html │ └── text.html ├── main.js ├── package-lock.json ├── package.json ├── public │ ├── es6.js │ ├── expression.js │ ├── index.html │ ├── oop.js │ ├── 完整的原型链.jpg │ └── 寄生组合继承.jpg ├── server.js ├── src │ ├── index.js │ ├── print.js │ └── styles.css ├── webpack.common.js ├── webpack.config.js ├── webpack.dev.js └── webpack.prod.js ├── laravel.md ├── level.md ├── levelGG.md ├── levelH2.md ├── levelH3.md ├── levelLI.md ├── linux-c ├── ch01程序的基本概念.md ├── ch02C基础.md ├── ch03gdb.md ├── ch04常用数据结构和算法.md ├── ch05计算机基础.md ├── ch06指针.md ├── ch07标准库.md ├── list.c ├── readme.md └── sh.c ├── linux.md ├── mongodb.md ├── mysql.md ├── mysqlH.md ├── nginx.md ├── node.md ├── php.md ├── php ├── DataStruct │ ├── BubbleSort.php │ ├── InsertSort.php │ ├── Judge.php │ ├── LinkList.php │ ├── LoopLink.php │ ├── Lottery.php │ ├── Node.php │ ├── QuickSort.php │ ├── RedPackage1.php │ ├── SelectSort.php │ ├── SortFactory.php │ └── SortInterface.php ├── Demo │ ├── Closure │ │ ├── ClosureBind.php │ │ ├── ClosureBindTo.php │ │ ├── closure.php │ │ └── 通过几个栗子认识PHP闭包.md │ ├── JavaPHP │ │ ├── Bicycle.php │ │ └── MountainBike.php │ ├── Old │ │ ├── ArrayToTree.php │ │ ├── Con.php │ │ ├── Factory.php │ │ ├── IteratorDemo.php │ │ ├── IteratorDemo2.php │ │ ├── Read.php │ │ ├── YieldDemo.php │ │ └── regex.php │ ├── PredefinedInterfaces │ │ ├── MyArrayAccess.php │ │ ├── MyIterator.php │ │ ├── MyIteratorAggregate.php │ │ ├── MySerializable.php │ │ └── MyTraversable.php │ ├── RabbitMQ │ │ ├── emit_log.php │ │ ├── emit_log_direct.php │ │ ├── emit_log_topic.php │ │ ├── new_task.php │ │ ├── new_task2.php │ │ ├── receive.php │ │ ├── receive_logs.php │ │ ├── receive_logs_direct.php │ │ ├── receive_logs_topic.php │ │ ├── rpc_client.php │ │ ├── rpc_server.php │ │ ├── send.php │ │ ├── worker.php │ │ └── worker2.php │ ├── Spider │ │ ├── ZiZhuZhang.php │ │ └── ZiZhuZhangRun.php │ └── Tools │ │ ├── generate.php │ │ ├── openbigFile.php │ │ └── preg.php ├── Ext │ ├── Date │ │ └── index.php │ ├── Dom │ │ ├── book.xml │ │ └── index.php │ └── Exif │ │ ├── P71005-185741.jpg │ │ └── index.php ├── Level │ ├── l │ │ ├── big.txt │ │ ├── big1.txt │ │ └── big2.txt │ ├── l1.php │ ├── php7.php │ └── sort.php ├── bootstrap.php ├── container │ ├── .gitignore │ ├── composer.json │ ├── composer.lock │ └── src │ │ ├── HelloInterface.php │ │ ├── container.php │ │ └── hello.php ├── index.php ├── laravel │ ├── Facade.md │ └── 服务容器.md └── modern │ ├── .gitignore │ ├── composer.json │ ├── composer.lock │ ├── logs │ ├── dev.log │ └── pro.log │ └── src │ ├── closure.php │ ├── config.php │ ├── exception.php │ ├── filter.php │ ├── log.php │ ├── pdo.php │ ├── scan.php │ └── urls.csv ├── public ├── img │ ├── explain.jpg │ ├── html+css │ │ ├── box.jpg │ │ ├── dom.jpg │ │ └── rule.jpg │ ├── http │ │ ├── attack.jpg │ │ ├── client1.jpg │ │ ├── client2.jpg │ │ ├── http_trans.jpg │ │ ├── http_trans2.jpg │ │ ├── request.jpg │ │ ├── response.jpg │ │ ├── three_way_handshanking.jpg │ │ └── uri.jpg │ ├── mysql_transaction.jpg │ ├── nf │ │ ├── 1nf.jpg │ │ ├── 1nfS.jpg │ │ ├── 2nf_e.jpg │ │ ├── 2nf_p.jpg │ │ ├── 2nf_p_e.jpg │ │ ├── 3nf_e.jpg │ │ └── 3nf_s.jpg │ ├── october │ │ ├── 文章组件.jpg │ │ └── 文章组件属性.jpg │ ├── process.jpg │ └── tcp-ip │ │ ├── arp.jpg │ │ ├── cast.jpg │ │ ├── data-head.jpg │ │ ├── dhcp.jpg │ │ ├── diff.jpg │ │ ├── dns.jpg │ │ ├── exchange.jpg │ │ ├── frame.jpg │ │ ├── ip.jpg │ │ ├── ipv6.jpg │ │ ├── layer.jpg │ │ ├── link.jpg │ │ ├── network.jpg │ │ ├── open.jpg │ │ ├── osi.jpg │ │ ├── packet.jpg │ │ ├── port.jpg │ │ ├── protocol.jpg │ │ ├── rarp.jpg │ │ ├── ssh.jpg │ │ ├── syn.jpg │ │ ├── t66y.jpg │ │ ├── tcp.jpg │ │ ├── telnet.jpg │ │ ├── udp.jpg │ │ ├── use.jpg │ │ └── wifi.jpg └── readme.md ├── redis.md ├── springboot.md ├── supervisor.md ├── tcp-ip.md ├── tests ├── LinkListTest.php ├── PredefinedInterfaces │ ├── ArrayAccessTest.php │ ├── ClosureTest.php │ ├── IteratorAggregateTest.php │ ├── IteratorTest.php │ ├── SerializableTest.php │ └── TraversableTest.php └── SortTest.php ├── 数据库范式.md └── 未命名绘图.drawio /.gitignore: -------------------------------------------------------------------------------- 1 | vendor 2 | .idea 3 | js/node_modules 4 | .vscode -------------------------------------------------------------------------------- /19level.md: -------------------------------------------------------------------------------- 1 | # 面试实践 2 | 3 | ## 杭州游戏公司 4 | 5 | ### 1、http请求响应时间过长,分析可能的原因以及对应的解决方法 6 | 7 | - DNS解析时间 8 | - 网络最小带宽 9 | - 大量数据库操作 10 | - 用很多javascript 11 | 12 | ### 2、状态码502问题,请求阻塞如何处理 13 | 14 | ### 3、lnmp优化 15 | 16 | ### 4、大流量请求,库存问题 17 | 18 | ### 5、生成环境异常处理问题 19 | 20 | ### 6、session与cookie原理问题 21 | 22 | ### 7、抽奖算法 23 | 24 | ### 8、sso单点登录 25 | 26 | ## 杭州电商公司 27 | 28 | ## 杭州教育公司 29 | 30 | 相谈甚欢,已入伍。 31 | 32 | ## 番外:Y在做什么 33 | 34 | Y是一家主周边游,轻国内和出境,外加社交的“互联网旅游”公司。 35 | 36 | 用户量逐年上升,这是毋庸置疑的,订单转化率是一直很头痛的问题,但是用户黏性还行,依托着杭州这座网红城市发家,活的还算滋润,18年疯狂扩张,养了10家子公司,啊哦,步子迈的太开,扯到蛋了,覆巢之下,岂有完卵,最终都是员工背锅。 37 | 38 | 本着又不是不能用的原则,4端开发风生水起,堪比基建狂魔,功能一个接一个,M公司有的我们必须要有,不然怎么显示我们高大上呢,19年攻坚计划,把M公司菜单搬过来,又不是不能用。。。好了,功能是能用了,架构已经稀烂了,php性能真烂,我们转java吧,这次是真的不能用了,哭唧唧 39 | 40 | 还别说,后台确实是要啥有啥,产品、订单、财务、计调、营销、运营、移动端、web端、系统。产品m站、小程序、pc、后台、bbs、摄影。两开花。 41 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 OMGZui 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /LeetCode.md: -------------------------------------------------------------------------------- 1 | # 算法思路 2 | 3 | ## 一、数组 4 | 5 | ### 1、TwoSum 6 | 7 | - 迭代 8 | - 利用哈希表Map存value和index 9 | 10 | ## 二、链表 11 | 12 | 应用:LRU 缓存 13 | 14 | ### 21、MergeTwoSortedLists 15 | 16 | - 迭代+双指针,哨兵头节点-1 17 | 18 | ### 206、ReverseLinkedList 19 | 20 | - 迭代+双指针,pre指针在前,cur指针为null,pre指针一直指向cur 21 | - 递归,f(n) = f(n-1) + f(1),递:头节点和剩余节点的解决方式,归:head.next.next = head; head.next = null; 22 | 23 | ### 141、LinkedListCycle 24 | 25 | - 快慢指针,fast.next.next == low.next; 26 | 27 | ## 三、栈 28 | 29 | 应用:函数调用、浏览器前进后退 30 | 31 | ### 20、ValidParentheses 32 | 33 | - 栈,左闭合进 右闭合出 34 | 35 | 36 | ## 四、队列 37 | 38 | 应用:阻塞队列、并发队列 39 | 40 | ## 五、排序 41 | 42 | ### 1、冒泡排序 43 | 44 | 冒泡排序只会操作相邻的两个数据。每次冒泡操作都会对相邻的两个元素进行比较,看是否满足大小关系要求。如果不满足就让它俩互换。一次冒泡会让至少一个元素移动到它应该在的位置,重复 n 次,就完成了 n 个数据的排序工作。 45 | 46 | ### 2、插入排序 47 | 48 | 插入算法的核心思想是取未排序区间中的元素,在已排序区间中找到合适的插入位置将其插入,并保证已排序区间数据一直有序。重复这个过程,直到未排序区间中元素为空,算法结束。 49 | 50 | ### 3、选择排序 51 | 52 | 选择排序每次会从未排序区间中找到最小的元素,将其放到已排序区间的末尾。 53 | 54 | ### 4、归并排序 55 | 56 | 我们先把数组从中间分成前后两部分,然后对前后两部分分别排序,再将排好序的两部分合并在一起,这样整个数组就都有序了。 57 | 58 | ### 5、快速排序* 59 | 60 | 如果要排序数组中下标从 p 到 r 之间的一组数据,我们选择 p 到 r 之间的任意一个数据作为 pivot(分区点)。 61 | 62 | ### 6、桶排序 63 | 64 | 将要排序的数据分到几个有序的桶里,每个桶里的数据再单独进行排序。桶内排完序之后,再把每个桶里的数据按照顺序依次取出,组成的序列就是有序的了。 65 | 66 | ### 7、计数排序 67 | 68 | 当要排序的 n 个数据,所处的范围并不大的时候,比如最大值是 k,我们就可以把数据划分成 k 个桶 69 | 70 | ### 8、基数排序 71 | 72 | 基数排序对要排序的数据是有要求的,需要可以分割出独立的“位”来比较,而且位之间有递进的关系,如果 a 数据的高位比 b 数据大,那剩下的低位就不用比较了。 73 | 74 | ## 六、查找 75 | 76 | ### 二分查找 77 | 78 | 二分查找针对的是一个有序的数据集合,查找思想有点类似分治思想。每次都通过跟区间的中间元素对比,将待查找的区间缩小为之前的一半,直到找到要查找的元素,或者区间被缩小为 0。 79 | 80 | ## 七、跳表 81 | 82 | 应用:Redis 中的有序集合(Sorted Set) 83 | 84 | 比较: 85 | 86 | - 按照区间来查找数据这个操作,红黑树的效率没有跳表高 87 | - 跳表更容易代码实现 88 | - 红黑树比跳表的出现要早一些,很多编程语言中的 Map 类型都是通过红黑树来实现的 89 | 90 | ## 八、散列表 91 | 92 | 应用:HashTable 93 | 94 | 解决散列冲突: 95 | 96 | - 开放寻址法 当数据量比较小、装载因子小的时候,适合采用开放寻址法。这也是 Java 中的ThreadLocalMap使用开放寻址法解决散列冲突的原因。 97 | - 链表法 基于链表的散列冲突处理方法比较适合存储大对象、大数据量的散列表,而且,比起开放寻址法,它更加灵活,支持更多的优化策略,比如用红黑树代替链表。 98 | 99 | ```java 100 | static final int hash(Object key) { 101 | int h; 102 | return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); 103 | } 104 | 105 | public int hashCode() { 106 | int h = hash; 107 | if (h == 0 && value.length > 0) { 108 | char val[] = value; 109 | 110 | for (int i = 0; i < value.length; i++) { 111 | h = 31 * h + val[i]; 112 | } 113 | hash = h; 114 | } 115 | return h; 116 | } 117 | 118 | 119 | ``` 120 | 121 | ## 九、哈希算法 122 | 123 | 应用:sha1、md5 124 | 125 | 具体场景: 126 | 127 | - 唯一标识 128 | - 数据完整性和正确性 129 | - 安全加密 130 | - 散列函数 131 | 132 | - 负载均衡 133 | - 数据分片 134 | - 分布式存储 135 | 136 | ## 十、二叉树 137 | 138 | 应用:二叉查找树 139 | 140 | ## 十一、红黑树 141 | 142 | ## 十二、堆 -------------------------------------------------------------------------------- /Mac新环境搭建.md: -------------------------------------------------------------------------------- 1 | # Mac新环境搭建 2 | 3 | ## 办公工具 4 | 5 | - 企业微信 6 | - 微信 7 | - Office 8 | - QQ 9 | - 搜狗拼音 10 | - 截图 11 | - Foxmail 12 | - 有道词典 13 | - 有道云笔记 14 | - Chrome 15 | 16 | ## 开发工具 17 | 18 | - PHPStorm 19 | - Navicat 20 | - Medis 21 | - Brew 22 | - Iterm2 23 | - OhMyZsh 24 | - Xcode 25 | - SourceTree 26 | - Docker 27 | - Spectacle 28 | - V2rayX 29 | - SublimeText 30 | - IstatMenus 31 | - XMindZen 32 | - Termius 33 | - Vscode 34 | 35 | ## 娱乐工具 36 | 37 | - 网易云音乐 38 | 39 | ## 参考 40 | 41 | - [Awesome Mac](https://github.com/jaywcjlove/awesome-mac/blob/master/README-zh.md) 42 | -------------------------------------------------------------------------------- /PHPStorm+Xdebug.md: -------------------------------------------------------------------------------- 1 | # PHPStorm+Xdebug 2 | 3 | 4 | 5 | - [PHPStorm+Xdebug](#phpstormxdebug) 6 | - [一、工具](#一工具) 7 | - [二、开箱](#二开箱) 8 | - [1、PHP配置](#1php配置) 9 | - [2、PHPStorm配置](#2phpstorm配置) 10 | - [三、成果](#三成果) 11 | - [四、参考文献](#四参考文献) 12 | 13 | 14 | 15 | ## 一、工具 16 | 17 | - PHPStorm 18 | - brew 19 | - php7.4 20 | - xdebug 21 | - zsh 22 | 23 | ## 二、开箱 24 | 25 | ### 1、PHP配置 26 | 27 | ```bash 28 | # 安装php7.4,替换本地的php 29 | brew install php 30 | echo 'export PATH="/usr/local/opt/php/sbin:$PATH"' >> ~/.zshrc 31 | source ~/.zshrc 32 | # 手动启动 33 | php-fpm -D 34 | # 暴力关闭 35 | killall php-fpm 36 | # 安装xdebug扩展,如果报错,一般是缺少依赖,直接brew install xxx即可 37 | pecl install xdebug 38 | # 查找php.ini,php-cli和php-fpm用的是同一个ini 39 | php --ini 40 | Configuration File (php.ini) Path: /usr/local/etc/php/7.4 41 | Loaded Configuration File: /usr/local/etc/php/7.4/php.ini 42 | Scan for additional .ini files in: /usr/local/etc/php/7.4/conf.d 43 | Additional .ini files parsed: /usr/local/etc/php/7.4/conf.d/ext-opcache.ini 44 | # 修改 45 | vim /usr/local/etc/php/7.4/php.ini 46 | [xdebug] 47 | ;我不会告诉你docker这里使用docker.for.mac.localhost 48 | xdebug.remote_host=localhost 49 | xdebug.remote_connect_back=0 50 | ;防止端口冲突 51 | xdebug.remote_port=9001 52 | ;标识 53 | xdebug.idekey=PHPSTORM 54 | xdebug.remote_autostart=1 55 | xdebug.remote_enable=1 56 | xdebug.cli_color=1 57 | xdebug.profiler_enable=0 58 | xdebug.remote_handler=dbgp 59 | xdebug.remote_mode=req 60 | ;确保这个日志文件存在 61 | xdebug.remote_log = /var/log/xdebug.log 62 | xdebug.var_display_max_children=-1 63 | xdebug.var_display_max_data=-1 64 | xdebug.var_display_max_depth=-1 65 | ``` 66 | 67 | ### 2、PHPStorm配置 68 | 69 | Q: 为什么用PHP Remote Debug 70 | 71 | A:可以不用下载浏览器xdebug插件 72 | 73 | ![从1开始的PHPStorm+Xdebug包搭建不包使用教程](https://cdn.learnku.com/uploads/images/202009/16/5373/UtASCBgToE.png!large) 74 | 75 | ![从1开始的PHPStorm+Xdebug包搭建不包使用教程](https://cdn.learnku.com/uploads/images/202009/16/5373/8AZHMb1HJr.png!large) 76 | 77 | ![从1开始的PHPStorm+Xdebug包搭建不包使用教程](https://cdn.learnku.com/uploads/images/202009/16/5373/klP1ujM6YS.png!large) 78 | 79 | ![从1开始的PHPStorm+Xdebug包搭建不包使用教程](https://cdn.learnku.com/uploads/images/202009/16/5373/P714DLzpMs.png!large) 80 | 81 | ![从1开始的PHPStorm+Xdebug包搭建不包使用教程](https://cdn.learnku.com/uploads/images/202009/16/5373/LafFFVRZkT.png!large) 82 | 83 | ## 三、成果 84 | 85 | ![从1开始的PHPStorm+Xdebug包搭建不包使用教程](https://cdn.learnku.com/uploads/images/202009/16/5373/k648VWBAxH.png!large) 86 | 87 | ## 四、参考文献 88 | 89 | 无 90 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 我的苹果笔记本 2 | 3 | ## 零、序言 4 | 5 | 平时积累的东西以笔记的形式分享出来 6 | 7 | ## Usage 8 | 9 | ### 目录结构 10 | 11 | ```bash 12 | 13 | - js 14 | - public js示例 15 | - main.js es6入口 16 | - src webpack示例 17 | - server.js webpack入口 18 | - webpack.*.js webpack配置文件 19 | - package.json 依赖管理 20 | 21 | - php 22 | - demo 各种栗子 23 | - ext php扩展包应用 24 | - container 容器 25 | - level 面试集合 26 | - bootstrap.php 入口 27 | - index.php 实例 28 | 29 | ``` 30 | 31 | ### 使用 32 | 33 | ```bash 34 | git clone https://github.com/OMGZui/noteBook.git 35 | 36 | # 前端 37 | cd js 38 | npm install 39 | node main.js 40 | # 浏览器 41 | http://localhost:5000/ 查看console 42 | # webpack 43 | npm run server 44 | http://localhost:3000/ 查看console 45 | 46 | # PHP 47 | cd php 48 | composer install 49 | php -S localhost:8000 50 | # 浏览器 51 | http://localhost:8000/php/index.php 52 | # 命令行 53 | php index.php 54 | 55 | # 测试 56 | vendor/bin/phpunit tests 57 | ``` 58 | 59 | ## 一、前端 60 | 61 | - [1、html+css](html+css.md) 62 | - [2、javascript](javascript.md) 63 | - [3、node](node.md) 64 | 65 | ## 二、后端 66 | 67 | - [1、linux](linux.md) 68 | - [2、nginx](nginx.md) 69 | - [3、mysql](mysql.md) 70 | - [4、php](php.md) 71 | - [5、redis](redis.md) 72 | - [6、mongodb](mongodb.md) 73 | 74 | ## 三、工具 75 | 76 | - [1、git](git.md) 77 | - [2、设计模式](https://github.com/OMGZui/DesignPattern) 78 | - [3、bash](https://github.com/OMGZui/bash-step-to-step) 79 | - [4、docker](https://github.com/OMGZui/lnmp) 80 | - [5、数据结构与算法](https://github.com/OMGZui/basic_c) 81 | - [6、leetcode](https://github.com/OMGZui/go_leetcode) 82 | - [7、supervisor](supervisor.md) 83 | - [8、PHPStorm+Xdebug](PHPStorm+Xdebug.md) 84 | 85 | ## 四、面试 86 | 87 | - [一个16年毕业生所经历的php面试](level.md) 88 | 89 | ## 五、书籍 90 | 91 | - [1、Linux C 一站式编程](linux-c) 92 | - [2、Elasticsearch: 权威指南](elasticSearch.md) 93 | - [3、图解HTTP](http.md) 94 | - [4、图解TCP/IP](tcp-ip.md) 95 | - [5、高性能Mysql](mysqlH.md) 96 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "omgzui/note-book", 3 | "description": "linux nginx mysql php http redis", 4 | "keywords": [ 5 | "php", 6 | "skill" 7 | ], 8 | "license": "MIT", 9 | "type": "project", 10 | "authors": [{ 11 | "name": "小粽子", 12 | "email": "862275679@qq.com" 13 | }], 14 | "minimum-stability": "stable", 15 | "require": { 16 | "php-amqplib/php-amqplib": "^2.8", 17 | "guzzlehttp/guzzle": "^6.3" 18 | }, 19 | "autoload": { 20 | "psr-4": { 21 | "PHP\\": "php/" 22 | }, 23 | "files": [ 24 | "helper.php" 25 | ] 26 | }, 27 | "require-dev": { 28 | "phpunit/phpunit": "^7.5", 29 | "symfony/var-dumper": "^4.2" 30 | }, 31 | "autoload-dev": { 32 | "psr-4": { 33 | "Tests\\": "tests/" 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /dev.sh: -------------------------------------------------------------------------------- 1 | #!/bin/zsh 2 | echo -n "输入你改动的内容:" 3 | read msg 4 | 5 | echo "---开始构建---\n" 6 | git add . 7 | git commit -m "$msg" 8 | git push origin master 9 | echo "\n---构建完成---" 10 | -------------------------------------------------------------------------------- /git.md: -------------------------------------------------------------------------------- 1 | # git简明教程 2 | 3 | 4 | 5 | - [git简明教程](#git简明教程) 6 | - [一、安装](#一安装) 7 | - [1、直接安装](#1直接安装) 8 | - [2、源码安装](#2源码安装) 9 | - [3、配置](#3配置) 10 | - [二、初始化](#二初始化) 11 | - [三、工作流](#三工作流) 12 | - [四、添加和提交](#四添加和提交) 13 | - [五、推送改动](#五推送改动) 14 | - [六、分支](#六分支) 15 | - [七、更新与合并](#七更新与合并) 16 | - [八、标签](#八标签) 17 | - [九、日志](#九日志) 18 | - [十、版本回退](#十版本回退) 19 | - [十一、使用技巧](#十一使用技巧) 20 | - [十二、参考资料](#十二参考资料) 21 | 22 | 23 | 24 | ## 一、安装 25 | 26 | ### 1、直接安装 27 | 28 | [下载](https://book.git-scm.com/downloads) 29 | 30 | ### 2、源码安装 31 | 32 | ```sh 33 | 34 | # 下载源码包 35 | wget https://www.kernel.org/pub/software/scm/git/git-2.9.5.tar.gz 36 | # 解压 37 | tar zxvf git-2.9.5 38 | # 依赖包 39 | yum -y install curl-devel expat-devel gettext-devel openssl-devel zlib-devel asciidoc xmlto docbook2x perl-devel 40 | # 进入开始编译 41 | cd git-2.9.5 42 | # 简易安装 43 | ./configure --prefix=/usr/local/git && make && make install 44 | # doc一起安装 45 | make configure && ./configure --prefix=/usr/local/git && make all && make install 46 | ``` 47 | 48 | ### 3、配置 49 | 50 | ```sh 51 | # 配置 52 | git config --global user.name "omgzui" 53 | git config --global user.email "862275679@qq.com" 54 | # .ssh 55 | ssh-keygen -t rsa -C "862275679@qq.com" 56 | # 用公钥关联远程仓库 57 | cat .ssh/id_rsa.pub 58 | 复制填入对应的git仓库 59 | ``` 60 | 61 | ## 二、初始化 62 | 63 | ```sh 64 | 65 | # 初始化仓库 66 | git init 67 | # 克隆仓库 68 | 本地克隆 69 | git clone /Users/shengj/mac/php/noteBook 70 | 远程克隆 71 | git clone https://github.com/OMGZui/noteBook 72 | 73 | ``` 74 | 75 | ## 三、工作流 76 | 77 | 你的本地仓库由 git 维护的三棵“树”组成。 78 | 79 | - 第一个是你的 `工作目录`,它持有实际文件 80 | - 第二个是 `暂存区(Index`),它像个缓存区域,临时保存你的改动 81 | - 最后是 `HEAD`,它指向你最后一次提交的结果 82 | 83 | ![](http://omgzui.oss-cn-hangzhou.aliyuncs.com/github/git-flow.jpg) 84 | 85 | ## 四、添加和提交 86 | 87 | ```sh 88 | 你可以提出更改(把它们添加到暂存区) 89 | # 添加 90 | # 某个文件 91 | git add git.md 92 | # 全部文件 93 | git add . 94 | 或者 95 | git add * 96 | 97 | 实际提交改动 98 | # 提交 99 | git commit -m '代码提交信息' 100 | 你的改动已经提交到了 HEAD,但是还没到你的远端仓库 101 | ``` 102 | 103 | ## 五、推送改动 104 | 105 | ```sh 106 | 107 | 提交到远端仓库 108 | # 推送 109 | git push origin master 110 | 111 | 如果你还没有克隆现有仓库,并欲将你的仓库连接到某个远程服务器 112 | # 添加远程服务器 113 | git remote add origin https://github.com/OMGZui/noteBook 114 | ``` 115 | 116 | ## 六、分支 117 | 118 | 分支是用来将特性开发绝缘开来的。在你创建仓库的时候,master 是“默认的”分支。在其他分支上进行开发,完成后再将它们合并到主分支上。 119 | 120 | ![](http://omgzui.oss-cn-hangzhou.aliyuncs.com/github/git-branch.jpg) 121 | 122 | ```sh 123 | 124 | # 创建一个叫做“bug_fix”的分支,并切换过去 125 | git checkout -b bug_fix 126 | # 切换回主分支 127 | git checkout master 128 | # 再把新建的分支删掉 129 | git branch -d bug_fix 130 | # 除非你将分支推送到远端仓库,不然该分支就是 不为他人所见的 131 | git push origin bug_fix 132 | ``` 133 | 134 | ## 七、更新与合并 135 | 136 | 在master合并bug_fix分支 137 | 138 | ```sh 139 | # 要更新你的本地仓库至最新改动,执行: 140 | git pull 141 | # 以在你的工作目录中 获取(fetch) 并 合并(merge) 远端的改动。 142 | # 要合并其他分支到你的当前分支(例如 master),执行: 143 | git merge bug_fix 144 | # 在这两种情况下,git 都会尝试去自动合并改动。遗憾的是,这可能并非每次都成功,并可能出现冲突(conflicts)。 这时候就需要你修改这些文件来手动合并这些冲突(conflicts)。改完之后,你需要执行如下命令以将它们标记为合并成功: 145 | git add . 146 | # 在合并改动之前,你可以使用如下命令预览差异: 147 | git diff bug_fix master 148 | ``` 149 | 150 | ## 八、标签 151 | 152 | ```sh 153 | 154 | # 为软件发布创建标签是推荐的。这个概念早已存在,在 SVN 中也有。你可以执行如下命令创建一个叫做 v1.0.0 的标签: 155 | git tag v1.0.0 1b2e1d63ff 156 | # 1b2e1d63ff 是你想要标记的提交 ID 的前 10 位字符。可以使用下列命令获取提交 ID: 157 | git log 158 | # 你也可以使用少一点的提交 ID 前几位,只要它的指向具有唯一性。 159 | ``` 160 | 161 | ## 九、日志 162 | 163 | ```sh 164 | 165 | # 如果你想了解本地仓库的历史记录,最简单的命令就是使用 166 | git log 167 | # 你可以添加一些参数来修改他的输出,从而得到自己想要的结果。 只看某一个人的提交记录 168 | git log --author=shengj 169 | # 一个压缩后的每一条提交记录只占一行的输出 170 | git log --pretty=oneline 171 | # 或者你想通过 ASCII 艺术的树形结构来展示所有的分支, 每个分支都标示了他的名字和标签: 172 | git log --graph --oneline --decorate --all 173 | # 看看哪些文件改变了 174 | git log --name-status 175 | # 这些只是你可以使用的参数中很小的一部分。更多的信息,参考 176 | git log --help 177 | ``` 178 | 179 | ## 十、版本回退 180 | 181 | ```sh 182 | 183 | # 假如你操作失误(当然,这最好永远不要发生),你可以使用如下命令替换掉本地改动: 184 | git checkout -- 185 | # 此命令会使用 HEAD 中的最新内容替换掉你的工作目录中的文件。已添加到暂存区的改动以及新文件都不会受到影响。 186 | 187 | # 假如你想丢弃你在本地的所有改动与提交,可以到服务器上获取最新的版本历史,并将你本地主分支指向它: 188 | git fetch origin 189 | git reset --hard origin/master 190 | ``` 191 | 192 | ## 十一、使用技巧 193 | 194 | - 使用图形界面大大提升效率,Mac推荐`SourceTree` 195 | - 冲突解决 196 | 197 | > 经常在合并分支时出现冲突,解决冲突还是很容易的,时刻 `git pull` 是个好习惯,有工具的话,会自动提示的,提示冲突也别怕, 198 | > 可以先`git stash`缓存起来,然后 `git pull`,这时再 `git stash pop`把缓存内容拿出来,打开冲突文件,进行修改即可。 199 | 200 | - 反悔 201 | 202 | > 有这样的需求,我们上线了最新版本,但是功能还不成熟,给客户演示时需要暂时成熟的版本,此时我们可以有两种做法: 203 | > 204 | > 1、切回到成熟版本,合并到master分支上 205 | > 206 | > 2、备份master,查看log,回退到成熟提交点。 207 | 208 | - 简单部署脚本 209 | 210 | ```sh 211 | #!/usr/bin/env bash 212 | 213 | # 切分支到master 214 | echo '切分支到master' 215 | git checkout master 216 | 217 | # 合并dev分支内容 218 | echo '合并dev分支内容' 219 | git merge dev 220 | 221 | # 提交代码 222 | echo '提交代码' 223 | git add . 224 | 225 | # 提交至本地暂存区 226 | echo '提交至本地暂存区' 227 | git commit -m 'push' 228 | 229 | # 上传至远程仓库 230 | echo '上传至远程仓库' 231 | git push origin master 232 | 233 | # 完成后切回dev分支 234 | echo '完成后切回dev分支' 235 | git checkout dev 236 | ``` 237 | 238 | ## 十二、参考资料 239 | 240 | - [git - 简明指南](http://rogerdudler.github.io/git-guide/index.zh.html) 241 | -------------------------------------------------------------------------------- /helper.php: -------------------------------------------------------------------------------- 1 | 4 | 5 | - [html+css](#htmlcss) 6 | - [一、html](#一html) 7 | - [1、关于闭合标签](#1关于闭合标签) 8 | - [2、属性](#2属性) 9 | - [3、复合元素](#3复合元素) 10 | - [4、HTML文档剖析](#4html文档剖析) 11 | - [5、文档对象模型](#5文档对象模型) 12 | - [二、css](#二css) 13 | - [1、css工作原理](#1css工作原理) 14 | - [1、css规则](#1css规则) 15 | - [2、选择器](#2选择器) 16 | - [3、伪类](#3伪类) 17 | - [1、链接伪类](#1链接伪类) 18 | - [2、结构化伪类](#2结构化伪类) 19 | - [4、伪元素](#4伪元素) 20 | - [5、继承](#5继承) 21 | - [6、层叠](#6层叠) 22 | - [7、规则声明](#7规则声明) 23 | - [2、定位元素](#2定位元素) 24 | - [1、盒模型](#1盒模型) 25 | - [2、浮动和清除](#2浮动和清除) 26 | - [3、定位](#3定位) 27 | - [1、定义上下文](#1定义上下文) 28 | - [2、显示属性](#2显示属性) 29 | - [4、背景](#4背景) 30 | - [3、文字和文本](#3文字和文本) 31 | - [1、来源](#1来源) 32 | - [2、字体](#2字体) 33 | - [3、文本](#3文本) 34 | - [4、页面布局](#4页面布局) 35 | - [5、界面组件](#5界面组件) 36 | - [1、导航菜单](#1导航菜单) 37 | - [2、表单](#2表单) 38 | - [3、弹出层](#3弹出层) 39 | 40 | 41 | 42 | ## 一、html 43 | 44 | ### 1、关于闭合标签 45 | 46 | HTML5没有特殊要求,可以加可以不加,比如 47 | 48 | `` or `` 49 | 50 | ### 2、属性 51 | 52 | `` 53 | 54 | src(source)和alt(alternative)就是属性 55 | 56 | ### 3、复合元素 57 | 58 | - `

`这样的标题 59 | - ``这样的复合元素 60 | - `

`这样的嵌套标签 61 | 62 | ### 4、HTML文档剖析 63 | 64 | ```html 65 | # HTMl5语法编写的最简单HTML页面模板 66 | 67 | 68 | 69 | 70 | An HTML Template 71 | 72 | 73 | 74 | 75 | 76 | ``` 77 | 78 | ### 5、文档对象模型 79 | 80 | ![](public/img/html+css/dom.jpg) 81 | 82 | ## 二、css 83 | 84 | ### 1、css工作原理 85 | 86 | #### 1、css规则 87 | 88 | ![](public/img/html+css/rule.jpg) 89 | 90 | #### 2、选择器 91 | 92 | - 分组选择符 以`逗号`作为分隔符 93 | - 上下文选择符 以`空格`作为分隔符 94 | - 子选择符 以`>`作为分隔符 95 | - 紧密兄弟选择符 以`+`作为分隔符 96 | - 一般兄弟选择符 以`~`作为分隔符 97 | - 通用选择符 以`*`作为分隔符 98 | - id和class选择符 99 | - class 以`.`作为分隔符 **不唯一** 100 | - id 以`#`作为分隔符 **唯一** 101 | - 属性选择符 102 | - 属性名 img[src] 103 | - 属性值 img[src=""] 104 | 105 | #### 3、伪类 106 | 107 | ##### 1、链接伪类 108 | 109 | ```css 110 | 111 | a:link {color: black;} //等着用户点击 112 | a:visited {color: gray;} //用户点击过 113 | a:hover {text-decoration: none;} //鼠标悬停 114 | a:active {color: red;} //正在点击,鼠标没释放 115 | 116 | ``` 117 | 118 | - :focus 119 | - :target 120 | 121 | ##### 2、结构化伪类 122 | 123 | - :first-child 124 | - :last-child 125 | - :nth-child() 126 | 127 | #### 4、伪元素 128 | 129 | - ::first-letter 130 | - ::first-line 131 | - ::before 132 | - ::after 133 | 134 | #### 5、继承 135 | 136 | #### 6、层叠 137 | 138 | - 规则一:找到所有元素和属性的声明 139 | - 规则二:按照顺序和权重 !important; 140 | - 规则三:按元素优先级 **I-C-E** 141 | - 规则四:顺序决定权重 142 | 143 | #### 7、规则声明 144 | 145 | - 文本值 146 | - 数字值 147 | - 颜色值 148 | 149 | ### 2、定位元素 150 | 151 | - position 控制页面上元素的位置关系 152 | - display 控制元素是堆叠、并排、隐藏 153 | - float 控制元素组成多栏布局 154 | 155 | #### 1、盒模型 156 | 157 | ![](public/img/html+css/box.jpg) 158 | 159 | - 边框( border)。 可以设置边框的宽窄、样式和颜色。 160 | - 内边距( padding)。 可以设置盒子内容区与边框的间距。 161 | - 外边距( margin)。 可以设置盒子与相邻元素的间距。 162 | 163 | > **外边距叠加** 164 | > 165 | > 解释是有`一连串段落`用了相同的样式,那么第一段和最后一段的上外边距和下外边距决定了`这连串段落`与`其它元素`之间的间距, 166 | > 167 | > 那么中间的段落呢,根本不需要上外边距和下外边距加起来这么宽的间距。因此以`上外边距和下外边距`宽的为标准, 168 | 169 | #### 2、浮动和清除 170 | 171 | ```html 172 | 183 | 184 |
185 | ``` 186 | 187 | #### 3、定位 188 | 189 | - static 静态的,默认 190 | - relative 相对定位 191 | - absolute 绝对定位,会随着窗口移动 192 | - fixed 固定定位,不会随着窗口移动 193 | 194 | ##### 1、定义上下文 195 | 196 | absolute一般是参照body,但是如果把父元素设置为relative,那么就会参照父元素。 197 | 198 | ##### 2、显示属性 199 | 200 | - 块级元素 display: block 201 | - 行内元素 display: inline 202 | - 隐藏 display: none 回收空间 203 | - 隐藏 visibility: hidden 不回收空间 204 | - 显示 visibility: visible 205 | 206 | #### 4、背景 207 | 208 | - background 209 | - background-color 210 | - background-image 211 | - background-repeat 212 | - background-position 213 | - background-size 214 | - background-attachment 215 | - ... 216 | 217 | ### 3、文字和文本 218 | 219 | #### 1、来源 220 | 221 | - 用户机器安装的字体 222 | - 保存在第三方网站上的字体 link 223 | - 自己服务器上的字体 @font-face 224 | 225 | #### 2、字体 226 | 227 | - font 228 | - font-family 229 | - font-size 230 | - font-style 231 | - font-weight 232 | - font-variant 233 | 234 | #### 3、文本 235 | 236 | - text-indent 237 | - text-decoration 238 | - text-align 239 | - text-transform 240 | - letter-spacing 241 | - word-spacing 242 | - line-height 243 | - vertical-align 244 | 245 | [实例:文本排布](js/html/text.html) 246 | 247 | ### 4、页面布局 248 | 249 | - 固定宽度 960px合适 250 | - 流动 251 | - 弹性 252 | 253 | 布局高度一般设置auto 254 | 宽度需要精确设置 255 | 256 | [实例:页面布局](js/html/flow.html) 257 | 258 | ### 5、界面组件 259 | 260 | UI(User Interface) 261 | 262 | #### 1、导航菜单 263 | 264 | [实例:导航栏](js/html/nav.html) 265 | 266 | [实例:菜单](js/html/menu.html) 267 | 268 | #### 2、表单 269 | 270 | ```html 271 | 272 | 273 | ``` 274 | 275 | > for 属性 与 id 属性 通过 相同 的 值 关联 起来 后, 用户 点击 标注 文本 也可以 选择 单选 按钮 和 复选框。 276 | 277 | - text: 基本 的 单行 文本 框。 278 | - password: 文本 显示 为 掩 码。 279 | - checkbox: 复选框。 280 | - radio: 单选 按钮。 281 | - submit: 提交 表单 的 按钮。 282 | - time、 date、 search: HTML5 文本 框 的 变体。 283 | 284 | #### 3、弹出层 285 | 286 | - z-index 越大越上面,默认0,只对非static有效 287 | 288 | [实例:弹出层](js/html/menu.html) -------------------------------------------------------------------------------- /js/html/flow.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Flow 9 | 105 | 106 | 107 | 108 |
109 |
110 |

Header

111 |
112 | 113 | 116 | 117 |
118 |
119 |
120 | 121 |
122 |
123 |
124 |

125 |
126 |
127 |
128 |
129 |

130 |
131 |
132 |
133 |
134 |

135 |
136 |
137 |
138 | 139 |
140 |
141 |
142 |

1

143 |
144 |
145 |
146 |
147 |

2

148 |
149 |
150 |
151 |
152 |

3

153 |
154 |
155 |
156 |
157 |

4

158 |
159 |
160 |
161 |
162 |

A CSS

163 |
164 |
165 | 166 | 167 | -------------------------------------------------------------------------------- /js/html/form.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Form 9 | 10 | 11 | 12 |
13 | 14 | 15 |

请输入用户名

16 |
17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /js/html/layer.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Stylin' with CSS - Figure 6.24 Popup Overlay 7 | 70 | 71 | 72 | 73 |
74 |
75 |
76 |

Pink Platforms

77 | More info 78 |
79 |
80 |
81 |
82 |
83 |

Leopard Platforms

84 | More info 85 |
86 |
87 |
88 |
89 |
90 |

Red Platforms

91 | More info 92 |
93 |
94 | 95 | 96 | -------------------------------------------------------------------------------- /js/html/menu.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Menu 9 | 98 | 99 | 100 | 101 | 151 | 152 | -------------------------------------------------------------------------------- /js/html/nav.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Nav 9 | 59 | 60 | 61 | 62 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /js/html/text.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Text 9 | 79 | 80 | 81 | 82 |
83 |

CSS

84 |

CSS stands for Cascading Style Sheets. CSS controls the presentational aspects of your Web pages.

85 |

Block-Level Elements

86 |

Block-level elements stack down the page. They include:

87 |
    88 |
  • 89 | header 90 |
  • 91 |
  • 92 | section 93 |
  • 94 |
  • 95 | h1, h2, etc. 96 |
  • 97 |
98 |

Inline Elements

99 |

Inline elements sit next to each other, if there is room. They include:

100 |
    101 |
  • 102 | img 103 |
  • 104 |
  • 105 | a 106 |
  • 107 |
  • 108 | em 109 |
  • 110 |
111 |
112 | Typography maketh the Web site. 113 | CWS 114 |
115 |
116 | 117 | 118 | 119 | -------------------------------------------------------------------------------- /js/main.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: 小粽子 3 | * @Date: 2017-12-02 21:39:29 4 | * @Last Modified by: 小粽子 5 | * @Last Modified time: 2017-12-11 21:29:35 6 | */ 7 | 8 | var express = require('express'); 9 | var app = express(); 10 | 11 | 12 | app.use(express.static('public')); 13 | 14 | app.listen(5000, function () { 15 | console.log('port 5000!'); 16 | }) -------------------------------------------------------------------------------- /js/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "js", 3 | "version": "1.0.0", 4 | "description": "js", 5 | "main": "main.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "watch": "webpack --watch", 9 | "start": "webpack-dev-server --open --config webpack.config.js", 10 | "build": "webpack --config webpack.prod.js", 11 | "server": "node server.js" 12 | }, 13 | "author": "小粽子", 14 | "license": "MIT", 15 | "dependencies": { 16 | "express": "^4.16.2", 17 | "lodash": "^4.17.4" 18 | }, 19 | "devDependencies": { 20 | "clean-webpack-plugin": "^0.1.17", 21 | "css-loader": "^0.28.7", 22 | "csv-loader": "^2.1.1", 23 | "express": "^4.16.2", 24 | "file-loader": "^1.1.5", 25 | "html-webpack-plugin": "^2.30.1", 26 | "style-loader": "^0.19.0", 27 | "webpack": "^3.10.0", 28 | "webpack-dev-middleware": "^1.12.2", 29 | "webpack-dev-server": "^2.9.7", 30 | "webpack-merge": "^4.1.1", 31 | "xml-loader": "^1.2.1" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /js/public/expression.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: 小粽子 3 | * @Date: 2017-12-04 20:09:21 4 | * @Last Modified by: 小粽子 5 | * @Last Modified time: 2017-12-04 21:47:45 6 | */ 7 | 8 | // 函数表达式 # 函数声明 9 | function functionName1(arg) {} 10 | // console.log(functionName1.name) //functionName1 11 | // # 函数表达式 12 | var functionName2 = function (arg) {} 13 | // console.log(functionName2.name) //functionName2 14 | 15 | // # 递归 16 | function factorial(num) { 17 | if (num <= 1) { 18 | return 1 19 | } 20 | return num + factorial(num - 1) 21 | } 22 | 23 | function factorial_better(num) { 24 | if (num <= 1) { 25 | return 1 26 | } 27 | return num + arguments.callee(num - 1) 28 | } 29 | 30 | var factorial_best = (function f(num) { 31 | if (num <= 1) { 32 | return 1 33 | } 34 | return num + f(num - 1) 35 | }) 36 | 37 | // console.log(factorial(100)) //5050 38 | // console.log(factorial_better(100)) //5050 39 | // console.log(factorial_best(100)) //5050 40 | 41 | // # 全局作用域 42 | // (function () { 43 | // var now = new Date() 44 | // if (now.getMonth() == 0 && now.getDate() == 1) { 45 | // console.log("Happy New Year!") 46 | // } 47 | // })() 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /js/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | js 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /js/public/完整的原型链.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OMGZui/noteBook/19d48d912e5e07271b370dbe00e498e5f18a29e7/js/public/完整的原型链.jpg -------------------------------------------------------------------------------- /js/public/寄生组合继承.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OMGZui/noteBook/19d48d912e5e07271b370dbe00e498e5f18a29e7/js/public/寄生组合继承.jpg -------------------------------------------------------------------------------- /js/server.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: 小粽子 3 | * @Date: 2017-12-11 20:24:24 4 | * @Last Modified by: 小粽子 5 | * @Last Modified time: 2017-12-11 20:24:24 6 | */ 7 | const express = require('express'); 8 | const webpack = require('webpack'); 9 | const webpackDevMiddleware = require('webpack-dev-middleware'); 10 | 11 | const app = express(); 12 | const config = require('./webpack.config.js'); 13 | const compiler = webpack(config); 14 | 15 | // Tell express to use the webpack-dev-middleware and use the webpack.config.js 16 | // configuration file as a base. 17 | app.use(webpackDevMiddleware(compiler, { 18 | publicPath: config.output.publicPath 19 | })); 20 | 21 | // Serve the files on port 3000. 22 | app.listen(3000, function () { 23 | console.log('Example app listening on port 3000!\n'); 24 | }); -------------------------------------------------------------------------------- /js/src/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: 小粽子 3 | * @Date: 2017-12-11 19:05:08 4 | * @Last Modified by: 小粽子 5 | * @Last Modified time: 2018-02-08 22:39:03 6 | */ 7 | import _ from 'lodash'; 8 | import printMe from './print.js'; 9 | import './styles.css'; 10 | 11 | function component() { 12 | var element = document.createElement('div'); 13 | var btn = document.createElement('button'); 14 | 15 | element.innerHTML = _.join([ 16 | 'Hello', 'webpack' 17 | ], ' '); 18 | 19 | btn.innerHTML = 'Click me and check the console!'; 20 | btn.onclick = printMe; 21 | 22 | element.appendChild(btn); 23 | 24 | return element; 25 | } 26 | 27 | let element = component(); // Store the element to re-render on print.js changes 28 | document.body.appendChild(element); 29 | 30 | if (module.hot) { 31 | module.hot.accept('./print.js', function () { 32 | 33 | console.log('Accepting the updated printMe module!'); 34 | document.body.removeChild(element); 35 | element = component(); // Re-render the "component" to update the click handler 36 | document.body.appendChild(element); 37 | }) 38 | } 39 | -------------------------------------------------------------------------------- /js/src/print.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: 小粽子 3 | * @Date: 2017-12-11 20:05:07 4 | * @Last Modified by: 小粽子 5 | * @Last Modified time: 2017-12-11 20:39:34 6 | */ 7 | 8 | export default function printMe() { 9 | console.log('Updating print.js...'); 10 | } -------------------------------------------------------------------------------- /js/src/styles.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-size: 22px; 3 | background: red; 4 | } -------------------------------------------------------------------------------- /js/webpack.common.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: 小粽子 3 | * @Date: 2017-12-11 20:49:53 4 | * @Last Modified by: 小粽子 5 | * @Last Modified time: 2017-12-11 20:50:15 6 | */ 7 | 8 | const path = require('path'); 9 | const CleanWebpackPlugin = require('clean-webpack-plugin'); 10 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 11 | 12 | module.exports = { 13 | entry: { 14 | app: './src/index.js' 15 | }, 16 | plugins: [ 17 | new CleanWebpackPlugin(['dist']), 18 | new HtmlWebpackPlugin({title: 'Production'}) 19 | ], 20 | output: { 21 | filename: '[name].bundle.js', 22 | path: path.resolve(__dirname, 'dist') 23 | } 24 | }; -------------------------------------------------------------------------------- /js/webpack.config.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: 小粽子 3 | * @Date: 2017-12-11 19:32:59 4 | * @Last Modified by: 小粽子 5 | * @Last Modified time: 2018-02-08 22:41:52 6 | */ 7 | 8 | const path = require('path'); 9 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 10 | const CleanWebpackPlugin = require('clean-webpack-plugin'); 11 | const webpack = require('webpack'); 12 | 13 | module.exports = { 14 | entry: { 15 | app: './src/index.js' 16 | }, 17 | devtool: 'inline-source-map', 18 | devServer: { 19 | contentBase: './dist', 20 | hot: true 21 | }, 22 | module: { 23 | rules: [ 24 | { 25 | test: /\.css$/, 26 | use: ['style-loader', 'css-loader'] 27 | } 28 | ] 29 | }, 30 | plugins: [ 31 | new HtmlWebpackPlugin({title: 'Output Management'}), 32 | new CleanWebpackPlugin(['dist']), 33 | new webpack.NamedModulesPlugin(), 34 | new webpack.HotModuleReplacementPlugin() 35 | ], 36 | output: { 37 | filename: '[name].bundle.js', 38 | path: path.resolve(__dirname, 'dist'), 39 | publicPath: '/' 40 | } 41 | }; -------------------------------------------------------------------------------- /js/webpack.dev.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: 小粽子 3 | * @Date: 2017-12-11 20:50:21 4 | * @Last Modified by: 小粽子 5 | * @Last Modified time: 2017-12-11 20:50:21 6 | */ 7 | 8 | const merge = require('webpack-merge'); 9 | const common = require('./webpack.common.js'); 10 | 11 | module.exports = merge(common, { 12 | devtool: 'inline-source-map', 13 | devServer: { 14 | contentBase: './dist' 15 | } 16 | }); -------------------------------------------------------------------------------- /js/webpack.prod.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: 小粽子 3 | * @Date: 2017-12-11 20:50:41 4 | * @Last Modified by: 小粽子 5 | * @Last Modified time: 2017-12-11 20:50:41 6 | */ 7 | 8 | const merge = require('webpack-merge'); 9 | const UglifyJSPlugin = require('uglifyjs-webpack-plugin'); 10 | const common = require('./webpack.common.js'); 11 | 12 | module.exports = merge(common, { 13 | plugins: [new UglifyJSPlugin()] 14 | }); -------------------------------------------------------------------------------- /laravel.md: -------------------------------------------------------------------------------- 1 | # Laravel 2 | 3 | ## Facade 4 | 5 | ```php 6 | public static function __callStatic($method, $args) 7 | { 8 | $instance = static::getFacadeRoot(); 9 | 10 | if (! $instance) { 11 | throw new RuntimeException('A facade root has not been set.'); 12 | } 13 | 14 | return $instance->$method(...$args); 15 | } 16 | 17 | public static function getFacadeRoot() 18 | { 19 | return static::resolveFacadeInstance(static::getFacadeAccessor()); 20 | } 21 | 22 | protected static function getFacadeAccessor() 23 | { 24 | return 'app'; 25 | } 26 | 27 | protected static function resolveFacadeInstance($name) 28 | { 29 | if (is_object($name)) { 30 | return $name; 31 | } 32 | 33 | if (isset(static::$resolvedInstance[$name])) { 34 | return static::$resolvedInstance[$name]; 35 | } 36 | 37 | return static::$resolvedInstance[$name] = static::$app[$name]; 38 | } 39 | ``` 40 | -------------------------------------------------------------------------------- /levelGG.md: -------------------------------------------------------------------------------- 1 | # 光光14问 2 | 3 | ## 1、队列 队列场景 几个队列对比 4 | 5 | 应用场景: 6 | 7 | 1. 异步处理 提高响应速度 发送短信、发送邮件 8 | 2. 应用解耦 两系统之间加入消息中间件 9 | 3. 流量削峰 用于秒杀系统 10 | 4. 日志处理 Kafka(收集日志)->Logstash(日志解析)->Elasticsearch(数据存储服务)->Kibana(数据可视化组件) 11 | 5. 消息通讯 12 | 13 | ## 2、锁的问题 并发锁怎么设计 乐观锁和悲观锁的设计 14 | 15 | redis并发锁:`redis->setnx(key, time);`,加上过期时间,避免死锁 16 | 17 | 秒杀系统设计: 18 | 19 | 1. 库存放入redis 20 | 2. 扣库存使用redis锁 21 | 3. 发货消息通过消息队列 22 | 4. 秒杀结束后同步数据库 23 | 24 | - 悲观锁:数据被外界修改保持保守态度,将数据处于锁定状态 25 | - 乐观锁:基于数据版本记录机制实现,MVCC 26 | 27 | 缓存雪崩:对缓存设置不同的过期时间、建立redis集群 28 | 29 | 缓存穿透:参数过滤和提醒并引导用户走我们的设置的键值、对不合法的参数进行空对象缓存并设置较短的过期时间 30 | 31 | redis淘汰策略:无法写入、移除最少使用的key、随机移除key、移除设置了过期时间中最少使用的key、随机移除设置了过期时间中的key、移除设置了过期时间中最早的key 32 | 33 | ## 3、数据问题 数据的隔离级别 以及一些接地气的比喻 索引的一些基本基础 能说出索引原理更加 34 | 35 | 索引类型:主键索引、单列索引、唯一索引、多列索引、全文索引 36 | 37 | 索引原理:B+Tree(平衡树) 38 | 39 | 聚簇索引:主索引直接存储行数据,次索引指向主索引 40 | 41 | 非聚簇索引:主索引和次索引指向物理行,由索引到磁盘拿数据(回行) 42 | 43 | 事务特性:原子性、一致性、隔离性、持久性 44 | 45 | 隔离级别: 46 | 47 | - 未提交读 会产生脏读 48 | - 已提交读 rc 其它数据库默认隔离级别 读不加锁,写、修改、删除加锁 49 | - 可重复读 rr mysql默认隔离级别 可能幻读 50 | - 可串行化 51 | 52 | ## 4、数据运维的问题 比如大表怎么拆分 读写分离的问题 主从问题(单主多从 多主多从) 53 | 54 | 一张表200w数据就比较慢了,慢查询优化 55 | 56 | 1. show processlist 查看语句 57 | 2. explain 查看 type 58 | 3. show profile 查看Sending data 59 | 60 | - 垂直分库:DB(user、order、product) -> DB(user)+DB(order)+DB(product) 61 | - 水平分库:DB(user)-> DB1(user)+DB2(user)+DB3(user) 62 | - 垂直分表:user(id、name、desc) -> user(id、name)+user(user_id、desc) 63 | - 水平分表:user -> user1+user2+user3 64 | 65 | ## 5、数据瓶颈问题 这里要牵扯出搜索引擎,比如目前es 或者一些 sphinx 66 | 67 | es基础: 68 | 69 | - `_index` 索引 相当于SQL中的`database` 70 | - `_type` 类型 相当于SQL中的`table` 71 | - `_id` 唯一标识 相当于SQL中的`id` 72 | 73 | es同步: 74 | 75 | - 定时任务同步数据,无法达到实时性 76 | - logstash+Elasticsearch-jdbc实时mysql同步 77 | 78 | ## 6、日志问题 如果能直接说出 完整elk的解决方案 更好 79 | 80 | 日志处理 Kafka(收集日志)->Logstash(日志解析)->Elasticsearch(数据存储服务)->Kibana(数据可视化组件) 81 | 82 | ## 7、性能排查问题 一些性能处理 xhporf(现在问的少了) 异常监控 一些傻逼行为规避 83 | 84 | ## 8、设计模式 能撸一些基本设计模式 更好 85 | 86 | ## 9、算法 我也只会一些基础 这个我也欠缺 87 | 88 | ## 10、数据结构 我也只会一些基础 我也欠缺 89 | 90 | ## 11、一些异步场景 怎么同步切换异步 91 | 92 | ## 12、网络层面 直接能熟悉swoole更好 因为我有swoole的项目经验 93 | 94 | ```sh 95 | # pid=22402为master进程 96 | # pid=22403为manager进程,子进程有8个worker进程和12个task进程 97 | UID PID PPID C STIME TTY TIME CMD 98 | root 22402 1 0 10:49 ? 00:00:00 swoft-http master process (/data1/work/houduan_test/zy_familyapi_test/www/bin/swoft) 99 | root 22403 22402 0 10:49 ? 00:00:00 swoft-http manager process 100 | root 22420 22403 0 10:49 ? 00:00:00 swoft-http task process 101 | root 22421 22403 0 10:49 ? 00:00:00 swoft-http task process 102 | root 22422 22403 0 10:49 ? 00:00:00 swoft-http task process 103 | root 22423 22403 0 10:49 ? 00:00:00 swoft-http task process 104 | root 22424 22403 0 10:49 ? 00:00:00 swoft-http task process 105 | root 22425 22403 0 10:49 ? 00:00:00 swoft-http task process 106 | root 22438 22403 0 10:49 ? 00:00:00 swoft-http task process 107 | root 22440 22403 0 10:49 ? 00:00:00 swoft-http task process 108 | root 22450 22403 0 10:49 ? 00:00:00 swoft-http task process 109 | root 22462 22403 0 10:49 ? 00:00:00 swoft-http task process 110 | root 22469 22403 0 10:49 ? 00:00:00 swoft-http task process 111 | root 22471 22403 0 10:49 ? 00:00:00 swoft-http task process 112 | root 22480 22403 0 10:49 ? 00:00:00 swoft-http worker process 113 | root 22489 22403 0 10:49 ? 00:00:00 swoft-http worker process 114 | root 22507 22403 0 10:49 ? 00:00:00 swoft-http worker process 115 | root 22521 22403 0 10:49 ? 00:00:00 swoft-http worker process 116 | root 22529 22403 0 10:49 ? 00:00:00 swoft-http worker process 117 | root 22537 22403 0 10:49 ? 00:00:00 swoft-http worker process 118 | root 22550 22403 0 10:49 ? 00:00:00 swoft-http worker process 119 | root 22560 22403 0 10:49 ? 00:00:00 swoft-http worker process 120 | ``` 121 | 122 | ## 13、微服务 docker k8s swarm 的一些经验更好 这个我只有微服务经验 123 | 124 | ## 14、服务器层面 nginx一些基本知识点 fpm知识点 一些服务器常用写法 比如sort 或者 xargs 一些基础 125 | -------------------------------------------------------------------------------- /levelH2.md: -------------------------------------------------------------------------------- 1 | # 3 年经验 PHP 准备面试 2 | 3 | 4 | 5 | - [3 年经验 PHP 准备面试](#3-%e5%b9%b4%e7%bb%8f%e9%aa%8c-php-%e5%87%86%e5%a4%87%e9%9d%a2%e8%af%95) 6 | - [1、引用变量](#1%e5%bc%95%e7%94%a8%e5%8f%98%e9%87%8f) 7 | - [2、unset](#2unset) 8 | - [3、对象赋值采用引用方式,不会写时复制,需要使用 clone 进行复制](#3%e5%af%b9%e8%b1%a1%e8%b5%8b%e5%80%bc%e9%87%87%e7%94%a8%e5%bc%95%e7%94%a8%e6%96%b9%e5%bc%8f%e4%b8%8d%e4%bc%9a%e5%86%99%e6%97%b6%e5%a4%8d%e5%88%b6%e9%9c%80%e8%a6%81%e4%bd%bf%e7%94%a8-clone-%e8%bf%9b%e8%a1%8c%e5%a4%8d%e5%88%b6) 9 | - [4、栗子1](#4%e6%a0%97%e5%ad%901) 10 | - [5、单引号和双引号](#5%e5%8d%95%e5%bc%95%e5%8f%b7%e5%92%8c%e5%8f%8c%e5%bc%95%e5%8f%b7) 11 | - [6、数据类型](#6%e6%95%b0%e6%8d%ae%e7%b1%bb%e5%9e%8b) 12 | - [7、超全局数组](#7%e8%b6%85%e5%85%a8%e5%b1%80%e6%95%b0%e7%bb%84) 13 | - [8、预定义变量](#8%e9%a2%84%e5%ae%9a%e4%b9%89%e5%8f%98%e9%87%8f) 14 | - [9、@错误控制符,==和===,++$a和$a++](#9%e9%94%99%e8%af%af%e6%8e%a7%e5%88%b6%e7%ac%a6%e5%92%8ca%e5%92%8ca) 15 | - [10、栗子2](#10%e6%a0%97%e5%ad%902) 16 | - [11、foreach 会 reset 重置指针,switch...case 有一个跳转表的概念](#11foreach-%e4%bc%9a-reset-%e9%87%8d%e7%bd%ae%e6%8c%87%e9%92%88switchcase-%e6%9c%89%e4%b8%80%e4%b8%aa%e8%b7%b3%e8%bd%ac%e8%a1%a8%e7%9a%84%e6%a6%82%e5%bf%b5) 17 | - [12、栗子3](#12%e6%a0%97%e5%ad%903) 18 | - [13、include 加载警告、require 加载致命错误](#13include-%e5%8a%a0%e8%bd%bd%e8%ad%a6%e5%91%8arequire-%e5%8a%a0%e8%bd%bd%e8%87%b4%e5%91%bd%e9%94%99%e8%af%af) 19 | - [14、正则表达式](#14%e6%ad%a3%e5%88%99%e8%a1%a8%e8%be%be%e5%bc%8f) 20 | - [15、文件](#15%e6%96%87%e4%bb%b6) 21 | - [16、http状态码](#16http%e7%8a%b6%e6%80%81%e7%a0%81) 22 | - [17、OSI 7层](#17osi-7%e5%b1%82) 23 | - [17、get与post区别](#17get%e4%b8%8epost%e5%8c%ba%e5%88%ab) 24 | - [18、nginx、fastcgi、php-fpm](#18nginxfastcgiphp-fpm) 25 | - [19、linux命令](#19linux%e5%91%bd%e4%bb%a4) 26 | - [20、mysql慢查询](#20mysql%e6%85%a2%e6%9f%a5%e8%af%a2) 27 | 28 | 29 | 30 | ## 1、引用变量 31 | 32 | &,指向一个变量的指针 33 | 34 | ## 2、unset 35 | 36 | unset 只会取消引用,不会销毁值 37 | 38 | ## 3、对象赋值采用引用方式,不会写时复制,需要使用 clone 进行复制 39 | 40 | ## 4、栗子1 41 | 42 | ```php 43 | $data = ['a', 'b', 'c']; 44 | foreach ($data as $key=>$val) 45 | { 46 | $val = &$data[$key]; 47 | var_dump($data); 48 | } 49 | 50 | var_dump($data); // [b,c,c] 51 | ``` 52 | 53 | ## 5、单引号和双引号 54 | 55 | - 双引号会解析变量 Heredoc 56 | - 单引号效率更高,Nowdoc 57 | 58 | ## 6、数据类型 59 | 60 | - 整数 integer 61 | - 浮点数 float、double 计算使用 bcmath 库,mysql 使用 decimal 字段 62 | - 字符串 string 63 | - 布尔 boolean 64 | 65 | - 数组 array 66 | - 对象 object 67 | - 回调 callback 68 | 69 | - 资源 resource 70 | - 空 null 赋值 null、未定义的变量、unset 销毁的变量 71 | 72 | ## 7、超全局数组 73 | 74 | - $SERVER['SERVER_ADDR'] 75 | - $SERVER['REMOTE_ADDR'] 76 | 77 | ## 8、预定义变量 78 | 79 | - **FILE** 80 | 81 | ## 9、@错误控制符,==和===,++$a和$a++ 82 | 83 | ## 10、栗子2 84 | 85 | ```php 86 | # 运算符优先级问题,++、>、||、= 87 | $a = 0; 88 | $b = 0; 89 | 90 | if ($a = 3 > 0 || $b = 3 > 0) 91 | { 92 | $a++; 93 | $b++; 94 | echo $a. "\n"; // 1 95 | echo $b. "\n"; // 1 96 | } 97 | ``` 98 | 99 | ## 11、foreach 会 reset 重置指针,switch...case 有一个跳转表的概念 100 | 101 | ## 12、栗子3 102 | 103 | ```php 104 | # static只会初始化一次,是局部的,会记录值 105 | $count = 5; 106 | function get_count() 107 | { 108 | static $count; 109 | return $count++; 110 | } 111 | 112 | echo $count; // 5 113 | ++$count; 114 | 115 | echo get_count(); // null 116 | echo get_count(); // 1 117 | 118 | ``` 119 | 120 | ## 13、include 加载警告、require 加载致命错误 121 | 122 | ## 14、正则表达式 123 | 124 | ```php 125 | # 后向引用 \\1 126 | $str = 'abc'; 127 | $pattern = '/(.*)<\/b>/'; 128 | preg_replace(pattern, '\\1', $str); 129 | 130 | # 贪婪模式 ?是取消贪婪 131 | $str = 'abcefg'; 132 | $pattern = '/.*?<\/b>/'; 133 | preg_match_all(pattern, '\\1', $str); 134 | 135 | # 实例:139开头的手机号码 136 | $pattern = '/^139\d{8}$/'; 137 | # 实例:取出html中img标签的所有src值 138 | $pattern = '//i' 139 | ``` 140 | 141 | ## 15、文件 142 | 143 | ```php 144 | # 对文本开头进行写内容 145 | function writeContent($file) 146 | { 147 | $handle = fopen(file, 'r'); 148 | $content = fread(handle, filesize(file)); 149 | $content = 'xxx'.$content; 150 | fclose($handle); 151 | 152 | $handle = fopen(file, 'w'); 153 | fwrite($handle, $content); 154 | fclose($handle); 155 | } 156 | 157 | # 对目录进行遍历 158 | function loopDir($dir) 159 | { 160 | $handle = opendir($dir); 161 | while(false !== ($file = readdir($handle))) 162 | { 163 | if($file != '.' && $file != '..') 164 | { 165 | if(filetype($dir.'/'.file) == 'dir') 166 | { 167 | loopDir($dir.'/'.file); 168 | } 169 | } 170 | } 171 | } 172 | 173 | ``` 174 | 175 | ## 16、http状态码 176 | 177 | - 499 客户端关闭了连接,nginx错误 178 | - 502 bad Gateway 请求过多,比如php-fpm处理不过来,导致无法正常响应 179 | - 504 Gateway time-out nginx超时 180 | 181 | ## 17、OSI 7层 182 | 183 | 1. 物理层 184 | 2. 数据链路层 185 | 3. 网络层 186 | 4. 传输层 tcp、udp 187 | 5. 会话层 188 | 6. 表示层 189 | 7. 应用层 http、ftp、dns 190 | 191 | ## 17、get与post区别 192 | 193 | - get可以存浏览器书签 194 | - get可以被缓存 195 | - get有数据长度限制,2048字符 196 | - get用于数据读取,幂等的 197 | - post用于修改数据,是非幂等的 198 | - post更安全 199 | - get只允许ASCII字符,post无限制 200 | 201 | ## 18、nginx、fastcgi、php-fpm 202 | 203 | nginx通过fastcgi协议与php-fpm通信 204 | 205 | ## 19、linux命令 206 | 207 | ps/top/kill/pstree 208 | 209 | 分 时 日 月 周 210 | * * * * * 211 | 212 | ## 20、mysql慢查询 213 | 214 | ```sql 215 | set profile=1; 216 | show profiles; 217 | show profile for query 1; 218 | 219 | explain 220 | ``` 221 | -------------------------------------------------------------------------------- /levelH3.md: -------------------------------------------------------------------------------- 1 | # 3年经验PHP算法思路总结 2 | 3 | ## 2、写一段代码判断单向链表中有没有形成环,如果形成环,请找出环的入口处,即P点 4 | 5 | Q:是否有环 6 | A:使用快慢指针,如果快指针能和慢指针相遇则有环 7 | 8 | Q:找出P点 9 | A:使用相遇的点和头结点同时移动,相遇则是P点 10 | 11 | ## 3、从扑克牌中随机抽5张牌,判断是不是一个顺子,即这5张牌是连续的 12 | 13 | 主要是考虑大小王的问题,我们可以把大小王当做0,数组排序后 14 | 15 | - 没有王,最大和最小值差4 16 | - 1张王,最大和最小值差4或者3 17 | - 2张王,最大和最小值差4或者3或者2 18 | 19 | ## 4、两条相交的单向链表,如何求它们的第一个公共节点 20 | 21 | ## 5、最长公共子序列问题LCS,如有[1,2,5,11,32,15,77]和[99,32,15,5,1,77]两个数组,找到它们共同都拥有的数,写出时间复杂度最优的代码,不能用array_intersect 22 | 23 | ## 6、二叉树前中后遍历代码 24 | 25 | ## 7、写个函数,判断下面扩号是否闭合,左右对称即为闭合: ((())),)(()),(()))),(((((()),(()()),()() 26 | 27 | 利用栈,左括号入栈,右括号出栈,如果出栈失败则不是闭合的 28 | 29 | ## 8、找出数组中不重复的值[1,2,3,3,2,1,5] 30 | 31 | ## 9、10瓶水,其中一瓶有毒,小白鼠喝完有毒的水之后,会在24小时后死亡,问:最少用几只小白鼠可以在24小时后找到具体是哪一瓶水有毒 32 | 33 | 二进制表示法,小白鼠死和活可以当做1和0,10的二进制是00001010,所以最少需要4只小白鼠 34 | 35 | ## 10、写一个一个程序来查找最长子串 36 | 37 | ## 11、什么是B+树,请画b+树的结构 38 | 39 | ## 12、写一段代码,找到所有子集合,如[a,b,c]的子集合有{},{a},{b},{c},{ab},{ac},{abc} 40 | 41 | ## 13、一个排序好的数组,将它从中间任意一个位置切分成两个数组,然后交换它们的位置并合并,合并后新数组元素如:20,21,22,25,30,1,2,3,5,6,7,8,15,18,19,写一个查询函数来查找某个值是否存在 42 | 43 | ## 14、斗地主中,地主比农民得到王炸的概率多多少 44 | 45 | ## 15、有这样一个字符串abcdefgkbcdefab随机长度,写一个函数来求bcde在这个字符串中出现的次数 46 | 47 | ## 16、在一个坐标系内有一个N个点组成的多边形,现在有一个坐标点,写代码或思路来判断这个点是否处于多边形内 48 | -------------------------------------------------------------------------------- /levelLI.md: -------------------------------------------------------------------------------- 1 | # 老李21问 2 | 3 | ## 1、PHP的垃圾回收机制以及大概实现 4 | 5 | 使用的是`引用计数` 6 | 7 | PHP底层数据结构`zval`中有个字节`refcount`,用以表示指向这个zval的变量个数,初始化是1,当php文件执行结束或使用`unset()`函数,`refcount`变为0时就会自动被系统销毁,实现垃圾回收 8 | 9 | ## 2、PHP7比PHP5节省资源(内存占用),大概是如何实现的 10 | 11 | PHP7优化了底层的数据结构和对Zend引擎的优化 12 | 13 | ## 3、PHP是弱语言类型,那么PHP中是如何实现类型转换的 14 | 15 | PHP的底层有个联合体`_zend_value`表示变量的类型,程序运行期间会根据自己的类型选择使用不同的成员 16 | 17 | ## 4、一个APP或者网页从发起并完成一个完整的HTTP流程大概是怎样的 18 | 19 | url->DNS域名解析->IP地址映射->TCP3次握手->HTTP请求->服务器处理http请求并返回http报文->浏览器渲染->结束 20 | 21 | ## 5、MYSQL的innodb引擎和MYISAM引擎有何不同,说出主要不同点 22 | 23 | - innodb支持行锁、事务、外键,而myisam只支持表锁 24 | - innodb是聚簇索引,myisam是非聚簇索引 25 | 26 | ## 6、MYSQL的innodb引擎中,聚簇索引和二级索引有什么不同,如何可以,请详细画出两种索引实现的数据结构以及不同 27 | 28 | 二级索引的叶子节点存的是主键值,而不是行指针 29 | 30 | ## 7、MYSQL的事务有几种隔离级别,分别是为了解决什么问题而出现 31 | 32 | 33 | 34 | 4中隔离级别: 35 | 36 | - 未提交读 37 | - 提交读,不可重复读 RC 其它数据库默认 38 | - 可重复读 RR mysql默认 39 | - 可串行化 40 | 41 | 主要是RC和RR,RC解决了脏读,是一个事务只能看到自己的修改,其它事务是看不到的,RR解决了不可重复读,同一个事务中多次读取同样的记录的结果是一样的。 42 | 43 | ## 8、MYSQL的锁是怎么回事,和事务之间有什么千丝万缕的联系 44 | 45 | 数据库事务有不同的隔离级别,不同的隔离级别对锁的使用是不同的,锁的应用最终导致不同事务的隔离级别。 46 | 47 | 悲观锁:正如其名,它指的是对数据被外界(包括本系统当前的其他事务,以及来自外部系统的事务处理)修改持保守态度,因此,在整个数据处理过程中,将数据处于锁定状态。 48 | 49 | 乐观锁:大多是基于数据版本( Version )记录机制实现【MVCC】 50 | 51 | 52 | 53 | ## 9、REDIS中常见的数据结构有几种?REIDS数据持久化有几种方案 54 | 55 | - string 字符串 56 | - list 列表 57 | - set 集合 58 | - zset 有序集合 59 | - hash 哈希 60 | 61 | 持久化有: 62 | 63 | - rdb 保存数据库中的键值对 rdb恢复更快,因为aof执行命令时间长 64 | - aof 保存服务器所执行的命令 优先aof 65 | 66 | ## 10、简述一下REDIS中,字符串、set、zset、list以及hash底层是如何实现的 67 | 68 | ## 11、REDIS中key的过期有几种策略,然后redis中key的过期是如何实现的 69 | 70 | expire key time(以秒为单位)–这是最常用的方式 71 | 72 | setex(String key, int seconds, String value)–字符串独有的方式 73 | 74 | 三种过期策略: 75 | 76 | - 定时删除 设置一个定时器,到了时间自动删除 77 | - 懒汉式式删除 获取key时进行删除 78 | - 定期删除 每隔一段时间进行key删除 79 | 80 | ## 12、你对微服务了解多少,如果你的经历中有这些信息,结合你的经历说说你们微服务是怎么做的 81 | 82 | ## 13、RPC了解多少,如果你经历过,结合你的经历说下你们RPC是通过什么协议实现的?消息格式是怎样的?采用哪种序列化方式 83 | 84 | RPC:远程过程调用协议,且不依赖于具体的网络传输协议,比如restful需要依赖http协议 85 | 86 | 87 | 88 | ## 14、TCP协议握手的过程 89 | 90 | 三次握手,四次挥手 91 | 92 | - Client发送SYN给Server 93 | - Server返回SYN/ACK给Client 94 | - Client返回ACK给Server 95 | 96 | 涉及到FIN_WAIT,CLOSE_WAIT 97 | 98 | - Client发送FIN给Server 99 | - Server收到FIN后返回ACK给Client 100 | - Server发送FIN给Client 101 | - Client收到FIN后发送ACK给Server 102 | 103 | ## 15、PHP异常你是如何使用的,简单说说 104 | 105 | - 网络请求接口 106 | - 耗时的计算 107 | - 数据库连接 108 | 109 | 通过捕捉异常避免系统崩溃,同时输出错误信息到日志有助于排查 110 | 111 | ## 16、SWOOLE的进程模型是什么样的?和LNMP有什么不同 112 | 113 | ![swoole](./public/img/process.jpg) 114 | 115 | 如图所知swoole的进程模型是一个Master进程和Manager进程组成 116 | 117 | Master进程是一个多线程进程,其中有一组非常重要的线程,叫做Reactor线程(组) 118 | 119 | Manager进程,某种意义上可以看做一个代理层,它本身并不直接处理业务,其主要工作是将Master进程中收到的数据转交给Worker进程,或者将Worker进程中希望发给客户端的数据转交给Master进程进行发送。 120 | 121 | Manager进程还负责监控Worker进程,如果Worker进程因为某些意外挂了,Manager进程会重新拉起新的Worker进程,有点像Supervisor的工作。而这个特性,也是最终实现热重载的核心机制。 122 | 123 | Worker进程其实就是处理各种业务工作的进程,Manager将数据包转交给Worker进程,然后Worker进程进行具体的处理,并根据实际情况将结果反馈给客户端。 124 | 125 | 当客户端连接的时候这个过程中,三种进程之间是怎么协作的: 126 | 127 | Client主动Connect的时候 128 | 129 | 1. Client实际上是与Master进程中的某个Reactor线程发生了连接。 130 | 2. 当TCP的三次握手成功了以后,由这个Reactor线程将连接成功的消息告诉Manager进程,再由Manager进程转交给Worker进程。 131 | 3. 在这个Worker进程中触发了OnConnect的方法。 132 | 133 | 当Client向Server发送了一个数据包的时候 134 | 135 | 1. 首先收到数据包的是Reactor线程,同时Reactor线程会完成组包,再将组好的包交给Manager进程,由Manager进程转交给Worker。 136 | 2. 此时Worker进程触发OnReceive事件。 137 | 3. 如果在Worker进程中做了什么处理,然后再用Send方法将数据发回给客户端时,数据则会沿着这个路径逆流而上。 138 | 139 | 140 | 141 | LNMP:主要是nginx与php-fpm的通信 142 | 143 | nginx作为一个代理服务器,通过fastcgi协议与php-fpm进行通信 144 | 145 | ## 17、同步、异步、阻塞、非阻塞和IO多路复用是怎么回事,常见的服务器进程(线程)模型有哪些 146 | 147 | 对于一个network IO (这里我们以read举例),它会涉及到两个系统对象,一个是调用这个IO的process (or thread),另一个就是系统内核(kernel)。当一个read操作发生时,它会经历两个阶段: 148 | 149 | 1. 等待数据准备 (Waiting for the data to be ready) 150 | 2. 将数据从内核拷贝到进程中 (Copying the data from the kernel to the process) 151 | 152 | 同步(synchronous):一次只能做一件事 153 | 异步(asynchronous):可以同时做多件事 154 | 阻塞(blocking):两个阶段都被block 155 | 非阻塞(non-blocking):两个阶段都没被block 156 | IO多路复用(IO multiplexing):select,epoll 157 | 158 | 159 | 160 | ## 18、计算机基础中常见的基础数据结构和基础算法 161 | 162 | - 链表 163 | - 栈 164 | - 队列 165 | - 树 166 | - 图 167 | - 哈希表 168 | 169 | - 排序 170 | - 查找 171 | 172 | ## 19、哈希一致性算法是怎么回事?同时说下redis集群有什么认识吗 173 | 174 | 一致性Hash算法是对2^32取模,形成一个哈希环 175 | 176 | 一致性Hash算法对于节点的增减都只需重定位环空间中的一小部分数据,具有较好的容错性和可扩展性。 177 | 178 | 179 | -------------------------------------------------------------------------------- /linux-c/ch01程序的基本概念.md: -------------------------------------------------------------------------------- 1 | # 程序的基本概念 2 | 3 | 4 | 5 | - [程序的基本概念](#程序的基本概念) 6 | - [1、程序由一系列指令组成](#1程序由一系列指令组成) 7 | - [2、编程语言](#2编程语言) 8 | 9 | 10 | 11 | ## 1、程序由一系列指令组成 12 | 13 | 程序由一系列指令组成, 指令是指示计算机进行某种运算的命令 14 | 15 | - 输入 16 | - 输出 17 | - 基本运算 18 | - 测试和分支 19 | - 循环 20 | 21 | ## 2、编程语言 22 | 23 | - 低级语言 直接用计算机指令编写程序 24 | - 机器语言 25 | - 汇编语言 26 | - 高级语言 用语句编写程序,语句是计算机指令抽象表示 27 | - c/c++ 28 | - java 29 | - php 30 | 31 | `a = b + 1` 语句要翻译成三条汇编指令或机器指令,这个过程称为**编译**,由编译器完成 32 | 33 | c语言是可移植的或称为与平台无关,不同编译器编译出来的指令特性可能不同 34 | 35 | program.c(源代码) =>(编译器进行编译为机器指令) => a.out(可执行文件) 36 | 37 | `bug`据说是早期计算机庞大,有一次不能正常工作了,工程师找了半天原因发现是一只臭虫钻进计算机导致的 38 | 39 | `debug`找到臭虫并消灭 40 | -------------------------------------------------------------------------------- /linux-c/ch02C基础.md: -------------------------------------------------------------------------------- 1 | # C基础 2 | 3 | 4 | 5 | - [C基础](#c基础) 6 | - [1、编码](#1编码) 7 | - [2、函数](#2函数) 8 | - [3、字符串](#3字符串) 9 | - [4、风格](#4风格) 10 | - [5、函数](#5函数) 11 | 12 | 13 | 14 | ## 1、编码 15 | 16 | 每个字符在计算机内部用一个整数表示,称为`字符编码` 17 | 18 | `'a'+1 = 'b'` == `97 + 1 = 98`,ASCII码运算得来 19 | 20 | ## 2、函数 21 | 22 | ```c 23 | // 标准库文件一般在/usr/inculde目录下 24 | #inclue 25 | 26 | // 标准main函数 27 | int main(int argc, char *argv[]){} 28 | ``` 29 | 30 | - 用户命令 /bin /usr/bin 31 | - 系统命令 /sbin /usr/sbin 需要root权限 32 | 33 | `Man Page`是Linux开发最常用的参考手册,包含很多section 34 | 35 | |section |描述 | 36 | |- |- | 37 | |1 |用户命令 ls(1) | 38 | |2 |系统调用 _exit(2) | 39 | |3 |库函数 printf(3) | 40 | |5 |系统配置文件的格式 passwd(5)| 41 | |8 |系统管理命令 ifconfig(8) | 42 | 43 | `增量式开发`是指将问题分解成多块,一块一块开发,如有关联,可先用伪代码填充 44 | 45 | ## 3、字符串 46 | 47 | 字符串字面值可以看做数组类型 48 | 49 | `char str[10] = "hello"` == `char str[10] = {'h','e','l','l','o','\0'}` `\0`即为NULL 50 | 51 | - `char c = "Hello"[0]` ✅ 可以通过类似数组访问字符 52 | - `"hello"[0] = 'A'` ❌ 不能修改字符 53 | 54 | ## 4、风格 55 | 56 | - i18n => internationalization => i 18个字母 n 57 | - count cnt 58 | - length len 59 | - window win 60 | - message msg 61 | - block blk 62 | - number nr 63 | - temporary temp tmp 64 | - trans x 65 | 66 | ## 5、函数 67 | 68 | 1. 函数应该只为了做一件事,增加复用性 69 | 2. 执行函数应该就是一个执行动作 70 | 3. 重要函数加注释 71 | -------------------------------------------------------------------------------- /linux-c/ch03gdb.md: -------------------------------------------------------------------------------- 1 | # gdb 2 | 3 | 4 | 5 | - [gdb](#gdb) 6 | - [1、调试的基本思路](#1调试的基本思路) 7 | - [2、单步执行和跟踪函数调用](#2单步执行和跟踪函数调用) 8 | - [3、断点](#3断点) 9 | - [4、观察点](#4观察点) 10 | 11 | 12 | 13 | ## 1、调试的基本思路 14 | 15 | 分析现象->假设错误原因->产生新的现象去验证假设 16 | 17 | ## 2、单步执行和跟踪函数调用 18 | 19 | |命令|描述| 20 | |-|-| 21 | |backtrace(bt)|查看各级函数及调用| 22 | |finish|连续运行到当前函数返回为止,然后停下来等待| 23 | |frame(f)|选择帧栈| 24 | |info(i) locals|查看当前帧栈局部变量的值| 25 | |list(l)|列出源码,每次10行| 26 | |next(n)|执行下一行语句| 27 | |print(p)|打印表达式的值| 28 | |quit(q)|退出gdb| 29 | |set var|设置变量的值| 30 | |start|开始执行程序| 31 | |step(s)|执行下一行语句,如果有函数调用,进入函数| 32 | 33 | ## 3、断点 34 | 35 | |命令|描述| 36 | |-|-| 37 | |break(b)行号 |在某一行设置断点| 38 | |continue(c) |从当前位置开始连续运行程序| 39 | |delete breakpoints 断点号 |删除某个断点| 40 | |display 变量名 |跟踪某个变量,每次停下都显示它的值| 41 | |disable breakpoint 断点号 |禁用某个断点| 42 | |enable 断点号 |启用某个断点号| 43 | |info(i) points |查看设置了哪些断点号| 44 | |run(r) |从头开始连续运行程序| 45 | 46 | ## 4、观察点 47 | 48 | |命令|描述| 49 | |-|-| 50 | |watch |设置观察点| 51 | |info(i) watchpoints |查看当前设置的观察点| 52 | |x |从某个位置开始打印,不区分哪个字节属于哪个变量| -------------------------------------------------------------------------------- /linux-c/ch04常用数据结构和算法.md: -------------------------------------------------------------------------------- 1 | # 常用数据结构和算法 2 | 3 | ## 1、算法 4 | 5 | 算法是用来解决一类计算问题的 6 | 7 | ## 2、链表 8 | 9 | ```c 10 | 11 | 12 | ``` -------------------------------------------------------------------------------- /linux-c/ch05计算机基础.md: -------------------------------------------------------------------------------- 1 | # 计算机基础 2 | 3 | ## 1、计算机中数的表示 4 | 5 | 计算机使用数字电路搭成的,数字电路中只有1和0两种状态 6 | 7 | 计算机中使用`逻辑电路`进行bit的运算 8 | 9 | 与门、或门、非门 异或门、与非门、或非门 10 | 11 | 23333,这TMD不是数电嘛 12 | 13 | ## 2、数据类型 14 | 15 | 宋老师吐槽js开发一个浏览器一个样,23333 16 | 17 | 1byte = 8bit 18 | 19 | 注:64位系统的差别 20 | 21 | - 字符 22 | - char 1字节 23 | - 整形 24 | - short 2字节 25 | - int 4字节 26 | - long 4字节 8字节 27 | - long long 8字节 8字节 28 | - 指针 4字节 8字节 29 | - 浮点型 30 | - float 4字节 31 | - double 8字节 32 | - long double 12字节 33 | 34 | ## 3、运算符 35 | 36 | - & 与 37 | - | 或 38 | - ^ 异或 39 | - ~ 取反 40 | - `>>` 右移 41 | - `<<` 左移 42 | 43 | ## 4、计算机体系基础 44 | 45 | 内存(Memory)包括数据和指令,每个内存单元有一个地址 46 | 47 | CPU(Central Processing Unit 中央处理器),CPU从内存取指令,然后解释执行,然后再取下一条指令,再解释执行 48 | 49 | CPU核心功能单元 50 | 51 | - 寄存器 52 | - 程序计数器 53 | - 指令译码器 54 | - 算数逻辑单元 55 | - 地址和数据总线 56 | 57 | MMU(Memory Management Unit 内存管理单元),如果没有MMU,内存地址直接传到内存芯片,称为`物理地址PA`,开启了MMU,则是内存地址被MMU截获,称为`虚拟地址VA`,这样做是有很大好处的 58 | 59 | CPU附近的存储器 60 | 61 | |存储器类型|位于哪里|存储容量|访问时间|如何访问| 62 | |-|-|-|-|-| 63 | |CPU寄存器|位于CPU执行单元|几十到几百字节|几纳秒|由指令决定| 64 | |Cache|位于CPU核中|几百KB到几MB|几十纳秒|寻址访问| 65 | |内存|位于CPU外的芯片|几百MB到几GB|几百纳秒|地址访问| 66 | |硬盘|位于设备总线|几百GB到几TB|几毫秒|驱动程序访问| 67 | 68 | ## 5、链接 69 | 70 | 在一个模块中,有些函数是提供给外部使用的,这些函数声明为`External Linkage 外链接` 71 | 72 | 有些函数只在模块内部使用而不希望被外界访问到,则声明为`Internal Linkage 内链接` 73 | 74 | 典型栗子 75 | 76 | ```c 77 | /** foo.c **/ 78 | static void foo(void); 79 | /** main.c **/ 80 | void foo(void); 81 | int main(void) 82 | { 83 | foo(); 84 | return 0; 85 | } 86 | 87 | ``` 88 | 89 | 以上链接`gcc foo.c main.c`在一起会报错,因为main.c中声明的foo应该是表示一个具有`外链接`的函数名,而foo.c 90 | 中声明的却是`内链接`,因为链接器找不到定义,无法确定它的地址,只好报错。 91 | 92 | `#include `尖括号头文件查找规则 93 | 94 | 1. /usr/local/include 95 | 2. /usr/lib/gcc/xxx-gnu/xxx/include 96 | 3. /usr/xxx-gnu/include 97 | 4. /usr/include 98 | 99 | `#include "stack.h"`引号头文件规则 `gcc -c main.c` 100 | 101 | 1. `main.c`当前目录查找`stack.h` 102 | 2. `-I 文件夹名字` 根据相对路径和绝对路径查找 103 | 104 | ## 6、共享库 105 | 106 | ```c 107 | # 查看进程地址空间 108 | ps 109 | 663 pts/0 00:00:00 zsh 110 | 808 pts/0 00:00:00 ps 111 | cat /proc/663/maps 112 | 55f7d57a2000-55f7d5865000 r-xp 00000000 fc:01 14385 /bin/zsh 113 | 55f7d5a65000-55f7d5a67000 r--p 000c3000 fc:01 14385 /bin/zsh 114 | 55f7d5a67000-55f7d5a6d000 rw-p 000c5000 fc:01 14385 /bin/zsh 115 | 55f7d5a6d000-55f7d5a81000 rw-p 00000000 00:00 0 116 | 55f7d75da000-55f7d7741000 rw-p 00000000 00:00 0 [heap] 117 | 7f2350ab2000-7f2350ac2000 r-xp 00000000 fc:01 786163 /usr/lib/x86_64-linux-gnu/zsh/5.4.2/zsh/computil.so 118 | 7f2350ac2000-7f2350cc1000 ---p 00010000 fc:01 786163 /usr/lib/x86_64-linux-gnu/zsh/5.4.2/zsh/computil.so 119 | . 120 | . 121 | . 122 | 7f2353a71000-7f2353a72000 r--p 00027000 fc:01 1035 /lib/x86_64-linux-gnu/ld-2.27.so 123 | 7f2353a72000-7f2353a73000 rw-p 00028000 fc:01 1035 /lib/x86_64-linux-gnu/ld-2.27.so 124 | 7f2353a73000-7f2353a74000 rw-p 00000000 00:00 0 125 | 7fff7a2d6000-7fff7a30e000 rw-p 00000000 00:00 0 [stack] 126 | 7fff7a367000-7fff7a36a000 r--p 00000000 00:00 0 [vvar] 127 | 7fff7a36a000-7fff7a36c000 r-xp 00000000 00:00 0 [vdso] 128 | ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall] 129 | ``` 130 | 131 | 1. `55f7d75da000-55f7d7741000 [heap]`堆空间 132 | 2. `7fff7a2d6000-7fff7a30e000 [stack]`栈空间 133 | 3. 堆空间的地址上限称为`break`,可以通过`系统调用brk`向`高地址`增长 134 | 4. 栈空间的`高地址`部分存在进程的环境变量和命令行参数,`低地址`才是真的栈空间,由高到低增长,显然没有堆空间富余,因此是可能用尽的 135 | 5. malloc分配空间需要一块很大的内存空间,显然没有足够大的`连续空闲内存`,所以可以分配多个不连续的PA映射到连续VA上 136 | 137 | ## 7、Makefile基础 138 | 139 | 有点难,先略过 -------------------------------------------------------------------------------- /linux-c/ch06指针.md: -------------------------------------------------------------------------------- 1 | # 指针 2 | 3 | ## 1、基本概念 4 | 5 | ```c 6 | int i; 7 | int *pi = &i; 8 | char c; 9 | char *pc = &c; 10 | 11 | & 表示取地址运算符 12 | &i 表示取变量i的地址 13 | int *pi = &i 表示定义一个指向int型的指针变量pi,并用i的地址来初始化pi 14 | * 表示指针间接寻址运算符 15 | *用在声明中表示声明了一个指针类型 int *pi = &i 16 | *用在表达式中是间接寻址符 *pi = *pi + 1 17 | ``` 18 | 19 | ## 2、栗子 20 | 21 | ### 1、字符串复制strcpy实现 22 | 23 | ```c 24 | #include 25 | #include 26 | 27 | // 字符串复制 28 | char *str_cpy(char *dst, const char *str) 29 | { 30 | // 断言,检测传入参数的合法性 31 | assert((dst != NULL) && (str != NULL)); 32 | // 临时指针 33 | char *tmp = dst; 34 | // 这里后面的分号意思是等到括号中条件结束 35 | while ((*tmp++ = *str++) != '\0'); 36 | return dst; 37 | } 38 | 39 | int main(int argc, char const *argv[]) 40 | { 41 | char *str = "hello"; 42 | char new_str[10]; 43 | str_cpy(new_str, str); 44 | printf("%s\n", new_str); 45 | return 0; 46 | } 47 | 48 | ``` -------------------------------------------------------------------------------- /linux-c/ch07标准库.md: -------------------------------------------------------------------------------- 1 | # 标准库 2 | 3 | ## 1、字符串操作 4 | 5 | ```c 6 | # 字符串赋初值 7 | char buf[10] => memset(buf, 0, 10) 8 | # 取字符串长度 9 | char buf[] = "hello" 10 | strlen(buf) = 5 //遇到'\0'返回,长度不包括'\0' 11 | ``` 12 | -------------------------------------------------------------------------------- /linux-c/list.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #define LEN(arr) ((sizeof(arr) / sizeof(*arr))) 7 | // 声明结点 8 | typedef struct NODE Node; 9 | struct NODE 10 | { 11 | Node *link; 12 | int value; 13 | }; 14 | 15 | // 根据数据创建单链表,并返回头结点 16 | Node *create(int *arr, int len) 17 | { 18 | // printf("%ld\n", sizeof(Node)); //16 这里为什么是16,是因为需要补齐 19 | // printf("%ld\n", sizeof(Node *)); // 8 20 | // printf("%ld\n", sizeof(int)); // 4 21 | // 头结点 22 | Node *head = (Node *)malloc(sizeof(Node)); 23 | // 下一个结点 24 | Node *next = head; 25 | next->link = NULL; 26 | 27 | int i; 28 | for (i = 0; i < len; i++) 29 | { 30 | // 新结点 31 | Node *new = (Node *)malloc(sizeof(Node)); 32 | new->value = *(arr + i); 33 | // 指向下一个结点 34 | next->link = new; 35 | new->link = NULL; 36 | // 新的下一个结点 37 | next = new; 38 | } 39 | return head; 40 | } 41 | 42 | // 遍历 43 | void show(Node *head) 44 | { 45 | Node *next = head->link; 46 | while (next != NULL) 47 | { 48 | // printf("链表的值=%d 地址=%p\n", next->value, next); 49 | printf("%d ", next->value); 50 | next = next->link; 51 | } 52 | printf("\n"); 53 | } 54 | 55 | // 插入 56 | bool insert(Node *head, int pos, int val) 57 | { 58 | Node *next = head; 59 | int i = 0; 60 | // 取到pos个位置的地址,为什么pos-1,是因为我们拿的是下一个地址 61 | while (next != NULL && i < pos - 1) 62 | { 63 | next = next->link; 64 | i++; 65 | } 66 | 67 | if (i > pos - 1 || next == NULL) 68 | { 69 | return false; 70 | } 71 | 72 | // 新结点 73 | Node *new = (Node *)malloc(sizeof(Node)); 74 | new->value = val; 75 | 76 | // 临时结点代表next的下一个结点 77 | Node *tmp = next->link; 78 | 79 | // 正式插入 80 | next->link = new; 81 | new->link = tmp; 82 | return true; 83 | } 84 | 85 | // 链表长度 86 | int length(Node * head) 87 | { 88 | int n = 0; 89 | Node * next = head->link; 90 | while(next != NULL) 91 | { 92 | n++; 93 | next = next->link; 94 | } 95 | return n; 96 | } 97 | 98 | int main(int argc, char const *argv[]) 99 | { 100 | int arr[] = {1, 2, 3, 4, 5, 10, 9, 8, 7, 6}; 101 | int len = LEN(arr); 102 | Node *head = create(arr, len); 103 | show(head); 104 | if (insert(head, 1, 100)) 105 | { 106 | show(head); 107 | printf("长度:%d\n", length(head)); 108 | } 109 | if (insert(head, 1, -100)) 110 | { 111 | show(head); 112 | printf("长度:%d\n", length(head)); 113 | } 114 | return 0; 115 | } 116 | -------------------------------------------------------------------------------- /linux-c/readme.md: -------------------------------------------------------------------------------- 1 | # Linux C 2 | 3 | ## 1、程序的基本概念 4 | 5 | [程序的基本概念](ch01程序的基本概念.md) 6 | 7 | ## 2、C基础 8 | 9 | [C基础](ch02C基础.md) 10 | 11 | ## 3、gdb 12 | 13 | [gdb](ch03gdb.md) 14 | 15 | ## 4、常用数据结构和算法 16 | 17 | [常用数据结构和算法](ch04常用数据结构和算法.md) 18 | 19 | ## 5、计算机基础 20 | 21 | [计算机基础](ch05计算机基础.md) 22 | 23 | ## 6、指针 24 | 25 | [指针](ch06指针.md) 26 | 27 | ## 7、标准库 28 | 29 | [标准库](ch07标准库.md) -------------------------------------------------------------------------------- /linux-c/sh.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define PI 3.14159265 6 | 7 | int main(int argc, char **argv) 8 | { 9 | int n = 0; 10 | double val = PI / 180; 11 | while (*++argv != NULL && **argv == '-') 12 | { 13 | // printf("%s\n", *argv); 14 | // printf("%c\n", *++*argv); 15 | switch (*++*argv) 16 | { 17 | case 'a': 18 | printf("参数:%c ", **argv); 19 | printf("%ld\n", time(NULL)); 20 | break; 21 | case 'b': 22 | printf("参数:%c ", **argv); 23 | printf("%f\n", sin(30 * val)); 24 | break; 25 | } 26 | n++; 27 | } 28 | if (n == 0) 29 | { 30 | printf("没有输入参数\n"); 31 | } 32 | return 0; 33 | } 34 | -------------------------------------------------------------------------------- /linux.md: -------------------------------------------------------------------------------- 1 | # linux 2 | 3 | 4 | 5 | - [linux](#linux) 6 | - [一、linux简介](#一linux简介) 7 | - [二、linux与windows对比](#二linux与windows对比) 8 | - [三、在vps中使用linux](#三在vps中使用linux) 9 | - [1、换源](#1换源) 10 | - [2、查看系统使用的Linux版本](#2查看系统使用的linux版本) 11 | - [3、配置防火墙 iptables](#3配置防火墙-iptables) 12 | - [4、配置远程连接 ssh](#4配置远程连接-ssh) 13 | - [5、清除登录日志](#5清除登录日志) 14 | - [6、查看linux上启动的服务](#6查看linux上启动的服务) 15 | - [四、linux服务器部署](#四linux服务器部署) 16 | - [五、参考资料](#五参考资料) 17 | 18 | 19 | 20 | ## 一、linux简介 21 | 22 | Linux(聆听i/ˈlɪnəks/ lin-əks)是一种自由和开放源码的类UNIX作业系统。目前运用领域最广泛、使用人数最多的操作系统。该操作系统的内核由林纳斯·托瓦兹在1991年10月5日首次发布。在加上使用者空间的应用程式之后,成为Linux作业系统。Linux也是自由软件和开放源代码软件发展中最著名的例子。只要遵循GNU通用公共许可证,任何个人和机构都可以自由地使用Linux的所有底层源代码,也可以自由地修改和再发布。大多数Linux系统还包括像提供GUI的X Window之类的程序。除了一部分专家之外,大多数人都是直接使用Linux发行版,而不是自己选择每一样组件或自行设置。 23 | 24 | ## 二、linux与windows对比 25 | 26 | - linux免费开源,windows商业付费 27 | - linux操作复杂,windows操作简单 28 | - linux适合程序员开发,windows适合一般人员 29 | - linux相对更安全高效 30 | 31 | ## 三、在vps中使用linux 32 | 33 | centos6 为例 34 | 35 | ### 1、换源 36 | 37 | ```sh 38 | 39 | mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup 40 | wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.163.com/.help/CentOS6-Base-163.repo 41 | yum clean all 42 | yum update 43 | 44 | ``` 45 | 46 | ### 2、查看系统使用的Linux版本 47 | 48 | ```sh 49 | 50 | # 内核版本 51 | cat /proc/version 52 | # 发行版本 53 | cat /etc/redhat-release 54 | 55 | ``` 56 | 57 | ### 3、配置防火墙 iptables 58 | 59 | ```sh 60 | 61 | # 保存至 /etc/sysconfig/iptables 62 | /etc/rc.d/init.d/iptables save 63 | # 写入规则 64 | # ssh服务器 65 | iptables -A INPUT -p tcp --dport 22 -j ACCEPT 66 | # ftp服务器 67 | iptables -A INPUT -p tcp --dport 21 -j ACCEPT 68 | # web服务器 69 | iptables -A INPUT -p tcp --dport 80 -j ACCEPT 70 | # mysql服务器 71 | iptables -A INPUT -p tcp --dport 3306 -j ACCEPT 72 | # 邮件服务器 73 | iptables -A INPUT -p tcp --dport 25 -j ACCEPT 74 | iptables -A INPUT -p tcp --dport 110 -j ACCEPT 75 | # DNS服务器 76 | iptables -A INPUT -p tcp --dport 53 -j ACCEPT 77 | # redis服务器 78 | iptables -A INPUT -p tcp --dport 6379 -j ACCEPT 79 | # 保存 80 | /etc/rc.d/init.d/iptables save 81 | # 重启 82 | service iptables restart 83 | 84 | ``` 85 | 86 | ### 4、配置远程连接 ssh 87 | 88 | ```sh 89 | 90 | vim /etc/ssh/sshd_config 91 | # 禁止root登陆 92 | #PermitRootLogin yes => PermitRootLogin no 93 | # 修改端口号 94 | #Port 22 => Port 1657 95 | service sshd restart 96 | 97 | ``` 98 | 99 | ### 5、清除登录日志 100 | 101 | ```sh 102 | 103 | # 用户最近登录信息的命令 104 | last命令,对应的日志文件/var/log/wtmp; 成功登录用户 105 | lastb命令,对应的日志文件/var/log/btmp; 尝试登录信息 106 | lastlog命令,对应的日志文件/var/log/lastlog; 显示最近登录信息 107 | 108 | # 清空日志文件 109 | echo > /var/log/wtmp 110 | echo > /var/log/btmp 111 | echo > /var/log/lastlog 112 | 113 | 清除Bash历史 114 | 115 | # 清除当前登录session的历史 116 | history -r 117 | # 清除所有历史 118 | history -cw 119 | 120 | ``` 121 | 122 | ### 6、查看linux上启动的服务 123 | 124 | ```sh 125 | 126 | # 查看系统运行的进程 127 | ps aux 128 | 129 | # 查看系统监听的服务 130 | netstat -antp 131 | 132 | # 查看当前所有服务的状态 133 | service --status-all 134 | 135 | ``` 136 | 137 | ## 四、linux服务器部署 138 | 139 | ## 五、参考资料 140 | -------------------------------------------------------------------------------- /mysqlH.md: -------------------------------------------------------------------------------- 1 | # 高性能MySQL 2 | 3 | 4 | 5 | - [高性能MySQL](#高性能mysql) 6 | - [一、mysql简介](#一mysql简介) 7 | - [1、mysql逻辑架构](#1mysql逻辑架构) 8 | - [2、并发控制](#2并发控制) 9 | - [3、事务](#3事务) 10 | - [4、隔离级别](#4隔离级别) 11 | - [5、死锁](#5死锁) 12 | - [6、多版本并发控制 MVCC](#6多版本并发控制-mvcc) 13 | - [7、存储引擎](#7存储引擎) 14 | - [二、mysql测试和性能](#二mysql测试和性能) 15 | - [三、mysql数据类型](#三mysql数据类型) 16 | - [1、选择优化的数据类型](#1选择优化的数据类型) 17 | - [2、整数类型](#2整数类型) 18 | - [3、实数类型](#3实数类型) 19 | - [4、字符串类型](#4字符串类型) 20 | - [5、日期和时间类型](#5日期和时间类型) 21 | - [6、范式与反范式](#6范式与反范式) 22 | - [四、mysql高性能索引](#四mysql高性能索引) 23 | - [1、索引基础](#1索引基础) 24 | - [2、高性能索引策略](#2高性能索引策略) 25 | - [独立的列](#独立的列) 26 | - [前缀索引和索引选择性](#前缀索引和索引选择性) 27 | - [多列索引](#多列索引) 28 | - [索引列顺序](#索引列顺序) 29 | - [聚簇索引](#聚簇索引) 30 | - [五、mysql查询性能优化](#五mysql查询性能优化) 31 | - [六、mysql高级特性](#六mysql高级特性) 32 | - [七、参考资料](#七参考资料) 33 | 34 | 35 | 36 | ## 一、mysql简介 37 | 38 | ### 1、mysql逻辑架构 39 | 40 | - 最上层,客户端 41 | 42 | 连接处理、授权认证、安全 43 | 44 | - 中间层,核心服务 45 | 46 | 查询解析、分析、优化、缓存、内置函数、存储引擎、触发器、视图 47 | 48 | - 最下层,存储引擎 49 | 50 | 存储引擎负责mysql中数据的存储和提取 51 | 52 | ### 2、并发控制 53 | 54 | - 每个客户端连接都会在服务器进程中拥有一个线程 55 | - MySQL会解析查询,并创建内部数据结构(解析树),然后对其进行各种优化,包括重写查询、决定表的读取顺序,以及选择合适的索引 56 | - 读锁又叫共享锁,多用户可以同一个时刻读取同一个资源,而互不干扰 57 | - 写锁又叫排它锁,同一个时刻只能有一个用户读写数据 58 | - 表锁,开销最小的策略 59 | - 行锁,最大程度支持并发处理,同时开销极大 60 | 61 | ### 3、事务 62 | 63 | 事务就是一组原子性的sql查询,事务内的语句,要么全部执行,要么全部执行失败 64 | 65 | ```sql 66 | start transaction; 67 | xxx 68 | rollback; 69 | commit; 70 | 71 | ``` 72 | 73 | ACID特性: 74 | 75 | - 原子性 A 76 | 77 | 事务要不就在执行中,要不然就是成功或者失败的状态 78 | 79 | - 一致性 C 80 | 81 | 执行事务过程中,所有对数据库写入的操作都应该是合法的,并不能产生不合法的数据状态 82 | 83 | - 隔离性 I 84 | 85 | 一个事务结束前,对另一个事务是不可见的 86 | 87 | - 持久性 D 88 | 89 | 一旦事务被提交,那么数据一定会被写入到数据库中并持久存储起来。 90 | 91 | ### 4、隔离级别 92 | 93 | - 未提交读 READ-UNCOMMITTED RU 94 | 95 | 事务可以读取未提交的数据,会产生脏读 96 | 97 | - 提交读 READ-COMMITTED RC 98 | 99 | 不可重复读,一个事务从开始到提交之前,所做的任何修改其他事物都是不可见的 100 | 101 | - 可重复读 REPEATABLE-READ RR 102 | 103 | mysql`默认`隔离级别,会产生幻读,意思是当事务在读取某个范围内的记录时,另外一个事务又在该范围内插入了新的记录 104 | 105 | - 可串行化 SERIALIZABLE 106 | 107 | 最高隔离级别 108 | 109 | ### 5、死锁 110 | 111 | 指两个或者多个事务在同一资源上相互占用,并请求锁定对方占用资源,从而导致恶性循环的现象 112 | 113 | 简单解决办法:将持有最少行级排他锁的事务进行回滚 114 | 115 | ### 6、多版本并发控制 MVCC 116 | 117 | 可以认为MVCC是行级锁的一个变种,并且在很多情况下避免了加锁操作,因此开销更低 118 | 119 | MVCC是通过保存数据在某个时间点的快照实现的 120 | 121 | 隐藏列,创建时间和过期时间,是系统版本号 122 | 123 | ### 7、存储引擎 124 | 125 | ```sql 126 | 127 | show table status like 'users'\G 128 | *************************** 1. row *************************** 129 | Name: users 130 | Engine: InnoDB 131 | Version: 10 132 | Row_format: Dynamic 133 | Rows: 0 134 | Avg_row_length: 0 135 | Data_length: 16384 136 | Max_data_length: 0 137 | Index_length: 0 138 | Data_free: 0 139 | Auto_increment: 2 140 | Create_time: 2019-03-06 22:15:42 141 | Update_time: NULL 142 | Check_time: NULL 143 | Collation: utf8mb4_unicode_ci 144 | Checksum: NULL 145 | Create_options: 146 | Comment: 147 | 1 row in set (0.05 sec) 148 | ``` 149 | 150 | ## 二、mysql测试和性能 151 | 152 | - 吞吐量 153 | - 响应时间或者延迟 154 | - 并发性 155 | - 可扩展性 156 | - 。。。 157 | 158 | ## 三、mysql数据类型 159 | 160 | ### 1、选择优化的数据类型 161 | 162 | - 更小的通常更好 163 | - 简单更好 164 | - 尽量避免NULL 165 | 166 | ### 2、整数类型 167 | 168 | 有符号范围:-2^(n-1)到2^(n-1)-1 169 | 170 | 无符号unsigned范围:0到2^(n-1+1)-1 171 | 172 | **注意:** `int(10)`和`int(1)`只是规定了`交互工具`来显示字符的个数,对于`存储和计算`来说,是一样的 173 | 174 | |类型|存储空间(字节)| 175 | |-|-| 176 | |tinyint|1| 177 | |smallint|2| 178 | |mediumint|3| 179 | |int|4| 180 | |bigint|8| 181 | 182 | ### 3、实数类型 183 | 184 | 精确运算用`decimal`类型 185 | 186 | |类型|存储空间(字节)| 187 | |-|-| 188 | |decimal|9【小数点左边4字节,小数点1字节,小数点右边4字节】| 189 | |float|4| 190 | |double|8| 191 | 192 | ### 4、字符串类型 193 | 194 | |类型|存储空间(字节)| 195 | |-|-| 196 | |varchar|n| 197 | |char|n| 198 | |blob|n| 199 | |text|n| 200 | |enum|n| 201 | 202 | ### 5、日期和时间类型 203 | 204 | - from_unixtime():将时间戳转换成日期 205 | - unix_timestamp():将日期转换成时间戳 206 | 207 | |类型|存储空间(字节)| 208 | |-|-| 209 | |timestamp|4| 210 | |datetime|8| 211 | 212 | ### 6、范式与反范式 213 | 214 | 范式的优点: 215 | 216 | - 更新操作更快 217 | - 很少的重复数据,只需要修改更少的数据 218 | - 表通常小,执行操作更快 219 | - 很少冗余数据,更少需要distinct或者group by操作 220 | 221 | 范式的缺点:schema通常需要关联 222 | 223 | 反范式的优点:避免关联 224 | 225 | ## 四、mysql高性能索引 226 | 227 | ### 1、索引基础 228 | 229 | 索引是存储引擎用于快速找到记录的一种数据结构 230 | 231 | 索引类型: 232 | 233 | - B-Tree(技术上说B+Tree) 234 | - 哈希索引 235 | 236 | 索引的优点: 237 | 238 | - 大大减少了服务器需要扫描的数据量 239 | - 可以帮助服务器避免排序和临时表 240 | - 可以将随机I/O变为顺序I/O 241 | 242 | ### 2、高性能索引策略 243 | 244 | #### 独立的列 245 | 246 | `select a_id from xx where a_id + 1 = 5;` 247 | 248 | 以上sql无法自动解析,所以不会走索引 249 | 250 | #### 前缀索引和索引选择性 251 | 252 | `select count(*) as cnt, left(city, 7) as pref from xxx group by pref order by cnt desc limit 10;` 253 | 254 | 选择合适的索引长度 255 | 256 | #### 多列索引 257 | 258 | 索引合并 259 | 260 | #### 索引列顺序 261 | 262 | 最左前缀原则 263 | 264 | #### 聚簇索引 265 | 266 | `聚簇索引`并不是一种单独的索引类型,而是一种数据存储方式 267 | 268 | 数据行实际上存放在索引的叶子页中,术语叫`聚簇` 269 | 270 | 索引列包含的是整数值 271 | 272 | - myisam主索引和次索引都指向物理行,比如id指向了物理行,由索引到磁盘拿数据(回行) 273 | - innodb在主索引行上直接存储行的数据,称为聚簇索引,次索引指向主索引,比如id行包括了name、age等等数据,name包括了id 274 | 275 | 索引覆盖:查找的字段正好是索引,速度快 276 | 277 | 延迟关联:让一部分数据走索引,比全表扫描好 278 | 279 | ## 五、mysql查询性能优化 280 | 281 | ## 六、mysql高级特性 282 | 283 | ## 七、参考资料 284 | -------------------------------------------------------------------------------- /node.md: -------------------------------------------------------------------------------- 1 | # node 2 | 3 | [node](https://github.com/OMGZui/node-demo) 4 | -------------------------------------------------------------------------------- /php/DataStruct/BubbleSort.php: -------------------------------------------------------------------------------- 1 | 0; $i--) { 19 | // 内层控制比较次数 20 | for ($j = 0; $j < $i; $j++) { 21 | if ($arr[$i] < $arr[$j]) { 22 | [$arr[$i], $arr[$j]] = [$arr[$j], $arr[$i]]; 23 | } 24 | } 25 | } 26 | return $arr; 27 | } 28 | } -------------------------------------------------------------------------------- /php/DataStruct/InsertSort.php: -------------------------------------------------------------------------------- 1 | = 0; $j--) { 21 | // 临时元素比当前元素小的话,进行移位,直到有序 22 | if ($temp < $arr[$j]) { 23 | $arr[$j + 1] = $arr[$j]; 24 | $arr[$j] = $temp; 25 | } 26 | } 27 | } 28 | return $arr; 29 | } 30 | } -------------------------------------------------------------------------------- /php/DataStruct/Judge.php: -------------------------------------------------------------------------------- 1 | create($arr); 17 | } 18 | 19 | private function create($arr) 20 | { 21 | $this->head = new Node(); 22 | $next = $this->head; 23 | for ($i = 0; $i < count($arr); $i++) { 24 | // 新结点 25 | $new = new Node(); 26 | $new->value = $arr[$i]; 27 | // 指向下一个结点 28 | $next->link = $new; 29 | $new->link = null; 30 | // 新的下一个结点 31 | $next = $new; 32 | } 33 | } 34 | 35 | public function show(Node $head) 36 | { 37 | $next = $head->link; 38 | while ($next != null) { 39 | echo $next->value . ' '; 40 | $next = $next->link; 41 | } 42 | } 43 | 44 | public function insert(Node $head, $pos, $val) 45 | { 46 | $next = $head; 47 | $i = 0; 48 | // 拿到第pos个结点的地址 49 | while ($i < $pos - 1 && $next != null) { 50 | $next = $next->link; 51 | $i++; 52 | } 53 | 54 | if ($i > $pos - 1 || $next == null) { 55 | return false; 56 | } 57 | 58 | // 新结点 59 | $new = new Node(); 60 | $new->value = $val; 61 | // 临时结点 62 | $tmp = $next->link; 63 | // 插入 64 | $next->link = $new; 65 | $new->link = $tmp; 66 | return true; 67 | } 68 | } 69 | 70 | -------------------------------------------------------------------------------- /php/DataStruct/LoopLink.php: -------------------------------------------------------------------------------- 1 | value == null) { 18 | return false; 19 | } 20 | 21 | // 快慢指针 22 | while ($fast->link != null && $fast->link->link != null) { 23 | //快指针一次走两步 24 | $fast = $fast->link->link; 25 | //慢指针一次走一步 26 | $slow = $slow->link; 27 | } 28 | 29 | if ($fast === $slow) { 30 | return true; 31 | } else { 32 | return false; 33 | } 34 | } 35 | 36 | // 找出p点,即环的入口 37 | public function link(Node $node) 38 | { 39 | $fast = $slow = $node; 40 | if ($node->value == null) { 41 | return null; 42 | } 43 | 44 | while ($fast->link != null && $fast->link->link != null) { 45 | //快指针一次走两步 46 | $fast = $fast->link->link; 47 | //慢指针一次走一步 48 | $slow = $slow->link; 49 | } 50 | 51 | //慢指针追上快指针,说明有环 52 | if ($fast === $slow) { 53 | $p1 = $node; 54 | $p2 = $fast; 55 | //p1指针指向head节点,p2指针指向它们第一次相交的点,然后两个指针每次移动一步,当它们再次相交,即为环的入口 56 | while ($p1 !== $p2) { 57 | $p1 = $p1->link; 58 | $p2 = $p2->link; 59 | } 60 | return $p1; //环的入口节点 61 | } else { 62 | return null; 63 | } 64 | } 65 | } -------------------------------------------------------------------------------- /php/DataStruct/Lottery.php: -------------------------------------------------------------------------------- 1 | StartTime = $this->getMicroTime(); 21 | } 22 | 23 | private function getMicroTime() 24 | { 25 | list($use, $sec) = explode(' ', microtime()); 26 | return ((float)$use + (float)$sec); 27 | } 28 | 29 | public function end() 30 | { 31 | $this->StopTime = $this->getMicroTime(); 32 | return round(($this->StopTime - $this->StartTime) * 1000, 1); 33 | } 34 | 35 | } 36 | 37 | //开始计时 38 | $runtime = new Lottery(); 39 | 40 | /* 41 | * 经典的概率算法, 42 | * $proArr是一个预先设置的数组, 43 | * 假设数组为:array(100,200,300,400), 44 | * 开始是从1,1000 这个概率范围内筛选第一个数是否在他的出现概率范围之内, 45 | * 如果不在,则将概率空间,也就是k的值减去刚刚的那个数字的概率空间, 46 | * 在本例当中就是减去100,也就是说第二个数是在1,900这个范围内筛选的。 47 | * 这样 筛选到最终,总会有一个数满足要求。 48 | * 就相当于去一个箱子里摸东西, 49 | * 第一个不是,第二个不是,第三个还不是,那最后一个一定是。 50 | * 这个算法简单,而且效率非常 高, 51 | * 关键是这个算法已在我们以前的项目中有应用,尤其是大数据量的项目中效率非常棒。 52 | */ 53 | function get_rand($prize_arr) 54 | { 55 | 56 | /* 57 | * 每次前端页面的请求,PHP循环奖项设置数组, 58 | * 通过概率计算函数get_rand获取抽中的奖项id。 59 | * 将中奖奖品保存在数组$res['yes']中, 60 | * 而剩下的未中奖的信息保存在$res['no']中, 61 | * 最后输出json个数数据给前端页面。 62 | */ 63 | $proArr = []; 64 | foreach ($prize_arr as $key => $val) { 65 | $proArr[$val['id']] = $val['v']; 66 | } 67 | 68 | $result = ''; 69 | //概率数组的总概率精度 70 | $proSum = array_sum($proArr); 71 | //概率数组循环 72 | foreach ($proArr as $key => $proCur) { 73 | $randNum = mt_rand(1, $proSum); 74 | if ($randNum <= $proCur) { 75 | $result = $key; 76 | break; 77 | } else { 78 | $proSum -= $proCur; 79 | } 80 | } 81 | unset ($proArr); 82 | 83 | $rid = $result; 84 | 85 | $res['yes'] = $prize_arr[$rid - 1]['prize']; //中奖项 86 | unset($prize_arr[$rid - 1]); //将中奖项从数组中剔除,剩下未中奖项 87 | shuffle($prize_arr); //打乱数组顺序 88 | $pr = []; 89 | for ($i = 0; $i < count($prize_arr); $i++) { 90 | $pr[] = $prize_arr[$i]['prize']; 91 | } 92 | $res['no'] = $pr; 93 | 94 | return $res; 95 | } 96 | 97 | 98 | /* 99 | * 奖项数组 100 | * 是一个二维数组,记录了所有本次抽奖的奖项信息, 101 | * 其中id表示中奖等级,prize表示奖品,v表示中奖概率。 102 | * 注意其中的v必须为整数,你可以将对应的 奖项的v设置成0,即意味着该奖项抽中的几率是0, 103 | * 数组中v的总和(基数),基数越大越能体现概率的准确性。 104 | * 本例中v的总和为100,那么平板电脑对应的 中奖概率就是1%, 105 | * 如果v的总和是10000,那中奖概率就是万分之一了。 106 | * 107 | */ 108 | $prize_arr = array( 109 | '0' => array('id' => 1, 'prize' => '平板电脑', 'v' => 1), 110 | '1' => array('id' => 2, 'prize' => '数码相机', 'v' => 5), 111 | '2' => array('id' => 3, 'prize' => '音箱设备', 'v' => 10), 112 | '3' => array('id' => 4, 'prize' => '4G优盘', 'v' => 50), 113 | '4' => array('id' => 5, 'prize' => '10Q币', 'v' => 100), 114 | '5' => array('id' => 6, 'prize' => '下次没准就能中哦', 'v' => 10000), 115 | ); 116 | 117 | $rid = []; 118 | for ($i = 0; $i < 10000; $i++) { 119 | $rid[] = get_rand($prize_arr); //根据概率获取奖项id 120 | } 121 | 122 | $n = count($rid); 123 | $arr = array_column($rid, 'yes'); 124 | 125 | $p = $s = $y = $four = $q = $x = 0; 126 | foreach ($arr as $item) { 127 | switch ($item) { 128 | case '平板电脑': 129 | $p++; 130 | break; 131 | case '数码相机': 132 | $s++; 133 | break; 134 | case '音箱设备': 135 | $y++; 136 | break; 137 | case '4G优盘': 138 | $four++; 139 | break; 140 | case '10Q币': 141 | $q++; 142 | break; 143 | case '下次没准就能中哦': 144 | $x++; 145 | break; 146 | } 147 | } 148 | 149 | function format($name, $num, $sum) 150 | { 151 | echo sprintf("{$num}人中奖,{$name}中奖率为:%.2f%%\n", $num / $sum * 100); 152 | } 153 | 154 | format('平板电脑', $p, $n); 155 | format('数码相机', $s, $n); 156 | format('音箱设备', $y, $n); 157 | format('4G优盘', $four, $n); 158 | format('10Q币', $q, $n); 159 | format('下次没准就能中哦', $x, $n); 160 | 161 | //计时结束 162 | echo "页面执行时间: " . $runtime->end() . " 毫秒"; -------------------------------------------------------------------------------- /php/DataStruct/Node.php: -------------------------------------------------------------------------------- 1 | value = $value; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /php/DataStruct/QuickSort.php: -------------------------------------------------------------------------------- 1 | sort($left); 36 | $right = $this->sort($right); 37 | 38 | return array_merge($left, [$base], $right); 39 | } 40 | } -------------------------------------------------------------------------------- /php/DataStruct/RedPackage1.php: -------------------------------------------------------------------------------- 1 | 8, 84 | 'totalMoney' => 10 85 | ]; 86 | $sent = 0.00; 87 | while ($packet['totalNum'] > 0) { 88 | $money = getRedPacket($packet); 89 | echo $money . ' '; 90 | $sent += $money; 91 | } 92 | echo $sent; -------------------------------------------------------------------------------- /php/DataStruct/SelectSort.php: -------------------------------------------------------------------------------- 1 | $arr[$j]) { 23 | $min = $j; 24 | } 25 | } 26 | 27 | // 交换位置,把实际上最小的值塞入arr[i] 28 | if ($min != $i) { 29 | [$arr[$min], $arr[$i]] = [$arr[$i], $arr[$min]]; 30 | } 31 | } 32 | 33 | return $arr; 34 | } 35 | } -------------------------------------------------------------------------------- /php/DataStruct/SortFactory.php: -------------------------------------------------------------------------------- 1 | methods[$name] = \Closure::bind($callback, $this, get_class()); 21 | } 22 | 23 | public function __call(string $name, array $arguments) 24 | { 25 | if (isset($this->methods[$name])) { 26 | return call_user_func_array($this->methods[$name], $arguments); 27 | } 28 | 29 | throw new \RuntimeException("不存在方法[{$name}]"); 30 | } 31 | 32 | } -------------------------------------------------------------------------------- /php/Demo/Closure/ClosureBindTo.php: -------------------------------------------------------------------------------- 1 | 1 && $arguments[0] instanceof \Closure) { 16 | return call_user_func_array($arguments[0]->bindTo($this), array_slice($arguments, 1)); 17 | } 18 | throw new \InvalidArgumentException("没有这个方法"); 19 | } 20 | } -------------------------------------------------------------------------------- /php/Demo/Closure/closure.php: -------------------------------------------------------------------------------- 1 | 4 | 5 | - [通过几个栗子认识PHP闭包](#通过几个栗子认识php闭包) 6 | - [一、栗子1 用作于回调](#一栗子1-用作于回调) 7 | - [二、栗子2 用作于变量赋值](#二栗子2-用作于变量赋值) 8 | - [三、栗子3 从父作用域继承变量](#三栗子3-从父作用域继承变量) 9 | - [四、栗子4的前提条件,简单理解`call_user_func_array()`和`call_user_func()`方法](#四栗子4的前提条件简单理解call_user_func_array和call_user_func方法) 10 | - [1. call_user_func — 把第一个参数作为回调函数调用](#1-call_user_func--把第一个参数作为回调函数调用) 11 | - [2. call_user_func_array — 调用回调函数,并把一个数组参数作为回调函数的参数](#2-call_user_func_array--调用回调函数并把一个数组参数作为回调函数的参数) 12 | - [五、栗子4 绑定闭包在指定对象](#五栗子4-绑定闭包在指定对象) 13 | - [1. Closure::bindTo — 复制当前闭包对象,绑定指定的$this对象和类作用域。](#1-closurebindto--复制当前闭包对象绑定指定的this对象和类作用域) 14 | - [2. Closure::bind — 复制一个闭包,绑定指定的$this对象和类作用域。](#2-closurebind--复制一个闭包绑定指定的this对象和类作用域) 15 | - [六、参考资料](#六参考资料) 16 | 17 | 18 | 19 | 有收获的话请**加颗小星星**,没有收获的话可以 **反对** **没有帮助** **举报**三连 20 | 21 | - [**示例代码**](https://github.com/OMGZui/noteBook/tree/master/php/Demo/Closure) 22 | - 本人能力有限,如遇到什么不对的地方还望指出修正,谢谢 23 | - 所有栗子的输出都使用`symfony/var-dumpe`美化了 24 | 25 | 匿名函数(Anonymous functions),也叫闭包函数(closures),允许 临时创建一个没有指定名称的函数。最经常用作回调函数(callback)参数的值。当然,也有其它应用的情况。 26 | 27 | 匿名函数目前是通过 Closure 类来实现的。 28 | 29 | ## 一、栗子1 用作于回调 30 | 31 | ```php 32 | $rs = preg_replace_callback('/-([a-z])/', function ($match) { 33 | return strtoupper($match[1]); 34 | }, 'hello-world'); 35 | 36 | dump($rs); // "helloWorld" 37 | ``` 38 | 39 | ## 二、栗子2 用作于变量赋值 40 | 41 | ```php 42 | $greet = function ($name) { 43 | dump($name); 44 | }; 45 | 46 | dump($greet instanceof Closure); // true 47 | $greet('PHP'); // "PHP" 48 | ``` 49 | 50 | ## 三、栗子3 从父作用域继承变量 51 | 52 | ```php 53 | $message = 'hello'; 54 | $example = function () use ($message) { 55 | dump($message); 56 | }; 57 | dump($example instanceof Closure); // true 58 | $example(); // "hello" 59 | ``` 60 | 61 | ## 四、栗子4的前提条件,简单理解`call_user_func_array()`和`call_user_func()`方法 62 | 63 | 64 | 65 | ### 1. call_user_func — 把第一个参数作为回调函数调用 66 | 67 | function call_user_func ($function, ...$parameter) {} 68 | 69 | 该方法接收多个参数,第一个就是回调函数,可以是`普通函数`,也可以是`闭包函数`,后面的`多个参数`都是作为函数回调使用 70 | 71 | ```php 72 | $rs = call_user_func(function (...$params) { 73 | return func_get_args(); 74 | }, 1, 2, 3); 75 | dump($rs); // [1,2,3] 76 | 77 | ``` 78 | 79 | ### 2. call_user_func_array — 调用回调函数,并把一个数组参数作为回调函数的参数 80 | 81 | function call_user_func_array ($function, array $param_arr) {} 82 | 83 | 该方法接收2个参数,第一个就是回调函数,可以是`普通函数`,也可以是`闭包函数`,后面的`数组参数`都是作为函数回调使用 84 | 85 | ```php 86 | $rs = call_user_func_array(function (array $params) { 87 | return func_get_args(); 88 | }, [1, 2, 3]); 89 | dump($rs); // [1,2,3] 90 | ``` 91 | 92 | ## 五、栗子4 绑定闭包在指定对象 93 | 94 | 楼主见解是将方法绑定到指定类上,使得方法也可以使用类的属性和方法,非常适合配合`__call()`魔术方法和`call_user_func_array`方法一起使用 95 | 96 | ### 1. Closure::bindTo — 复制当前闭包对象,绑定指定的$this对象和类作用域。 97 | 98 | function bindTo($newthis, $newscope = 'static') { } 99 | 100 | ```php 101 | 1 && $arguments[0] instanceof \Closure) { 109 | return call_user_func_array($arguments[0]->bindTo($this), array_slice($arguments, 1)); 110 | } 111 | throw new \InvalidArgumentException("没有这个方法"); 112 | } 113 | } 114 | 115 | // 测试 116 | public function testClosureBindTo() 117 | { 118 | $obj = new ClosureBindTo(); 119 | $this->assertEquals(2, $obj->add(function (array $params) { 120 | return ++$params[0]; 121 | }, [1])); 122 | 123 | // 测试同一个实例 124 | $newObj = $obj->test(function (array $params){ 125 | return $this; 126 | }, [1]); 127 | $this->assertTrue($newObj instanceof $obj); 128 | } 129 | 130 | ``` 131 | 132 | ### 2. Closure::bind — 复制一个闭包,绑定指定的$this对象和类作用域。 133 | 134 | static function bind(Closure $closure, $newthis, $newscope = 'static') { } 135 | 136 | bind函数是bindTo的静态表示 137 | 138 | ```php 139 | methods[$name] = \Closure::bind($callback, $this, get_class()); 152 | } 153 | 154 | public function __call(string $name, array $arguments) 155 | { 156 | if (isset($this->methods[$name])) { 157 | return call_user_func_array($this->methods[$name], $arguments); 158 | } 159 | 160 | throw new \RuntimeException("不存在方法[{$name}]"); 161 | } 162 | } 163 | 164 | // 测试 165 | public function testClosureBind() 166 | { 167 | $obj = new ClosureBind(); 168 | $obj->addMethod('add', function (array $params) { 169 | return ++$params[0]; 170 | }); 171 | $this->assertEquals(2, $obj->add([1])); 172 | 173 | // 测试同一个实例 174 | $obj->addMethod('test', function (array $params) { 175 | return $this; 176 | }); 177 | $this->assertTrue($obj->test([1]) instanceof $obj); 178 | } 179 | 180 | ``` 181 | 182 | ## 六、参考资料 183 | 184 | - [php手册](http://php.net/manual/zh/functions.anonymous.php) -------------------------------------------------------------------------------- /php/Demo/JavaPHP/Bicycle.php: -------------------------------------------------------------------------------- 1 | cadence = $startCadence; 22 | $this->speed = $startSpeed; 23 | $this->gear = $startGear; 24 | } 25 | 26 | // 设置踏板 27 | public function setCadence(int $newValue) 28 | { 29 | $this->cadence = $newValue; 30 | } 31 | 32 | // 设置齿轮 33 | public function setGear(int $newValue) 34 | { 35 | $this->gear = $newValue; 36 | } 37 | 38 | // 减速 39 | public function applyBrake(int $decrement) 40 | { 41 | $this->speed -= $decrement; 42 | } 43 | 44 | // 加速 45 | public function speedUp(int $increment) 46 | { 47 | $this->speed += $increment; 48 | } 49 | } 50 | 51 | $bicycle = new Bicycle(30, 0, 8); 52 | 53 | echo $bicycle->cadence." ".$bicycle->speed." ".$bicycle->gear."\n"; -------------------------------------------------------------------------------- /php/Demo/JavaPHP/MountainBike.php: -------------------------------------------------------------------------------- 1 | seatHeight = $startHeight; 19 | } 20 | 21 | 22 | public function setHeight(int $newValue) 23 | { 24 | $this->seatHeight = $newValue; 25 | } 26 | } -------------------------------------------------------------------------------- /php/Demo/Old/ArrayToTree.php: -------------------------------------------------------------------------------- 1 | [ 8 | 'id' => 1, 9 | 'pid' => 0, 10 | 'name' => '安徽省' 11 | ], 12 | 2 => [ 13 | 'id' => 2, 14 | 'pid' => 0, 15 | 'name' => '浙江省' 16 | ], 17 | 3 => [ 18 | 'id' => 3, 19 | 'pid' => 1, 20 | 'name' => '合肥市' 21 | ], 22 | 4 => [ 23 | 'id' => 4, 24 | 'pid' => 3, 25 | 'name' => '长丰县' 26 | ], 27 | 5 => [ 28 | 'id' => 5, 29 | 'pid' => 1, 30 | 'name' => '安庆市' 31 | ], 32 | ]; 33 | 34 | function generateTree($items) 35 | { 36 | $tree = []; 37 | foreach ($items as $item) { 38 | if (isset($items[$item['pid']])) { 39 | $items[$item['pid']]['children'][] = &$items[$item['id']]; 40 | } else { 41 | $tree[] = &$items[$item['id']]; 42 | } 43 | } 44 | return $tree; 45 | } 46 | 47 | //function generateTree($items) 48 | //{ 49 | // foreach ($items as $item) { 50 | // $items[$item['pid']]['children'][$item['id']] = &$items[$item['id']]; 51 | // } 52 | // return isset($items[0]['children']) ? $items[0]['children'] : []; 53 | //} 54 | 55 | dump(generateTree($items)); 56 | 57 | $tree = generateTree($items); 58 | function getTreeData($tree) 59 | { 60 | foreach ($tree as $t) { 61 | dump($t['name']); 62 | if (isset($t['children'])) { 63 | getTreeData($t['children']); 64 | } 65 | } 66 | } 67 | 68 | getTreeData($tree); 69 | -------------------------------------------------------------------------------- /php/Demo/Old/Con.php: -------------------------------------------------------------------------------- 1 | dsn = "mysql:dbname={$this->db};host={$this->host};port={$this->port}"; 32 | 33 | // $this->conn = new \mysqli($this->host, $this->user_name, $this->password, $this->db, $this->port); 34 | // if ($this->conn->connect_error) { 35 | // die('Fail' . $this->conn->connect_error); 36 | // } 37 | 38 | $this->pdo = new \PDO($this->dsn, $this->user_name, $this->password); 39 | } 40 | 41 | function addMysqli() 42 | { 43 | return $this->conn->query($this->add_sql); 44 | } 45 | 46 | // function selectMysqli() 47 | // { 48 | // $this->conn->set_charset('utf8'); 49 | // $rows = $this->conn->query($this->select_sql); 50 | // $rs = []; 51 | // while ($row = $rows->fetch_assoc()) { 52 | // $rs[] = $row; 53 | // } 54 | // return $rs; 55 | // } 56 | // 57 | // function closeMysqli() 58 | // { 59 | // return $this->conn->close(); 60 | // } 61 | 62 | function addPdo() 63 | { 64 | return $this->pdo->exec($this->add_sql); 65 | } 66 | 67 | function selectPdo() 68 | { 69 | $rows = []; 70 | foreach ($this->pdo->query($this->select_sql, \PDO::FETCH_ASSOC) as $row) { 71 | $rows[] = $row; 72 | } 73 | return $rows; 74 | } 75 | 76 | function closePdo() 77 | { 78 | unset($this->pdo); 79 | } 80 | } 81 | 82 | $db = new Con(); 83 | 84 | dump($db->selectPdo()); 85 | //$db->addPdo(); 86 | //dump($db->selectPdo()); 87 | $db->closePdo(); 88 | -------------------------------------------------------------------------------- /php/Demo/Old/Factory.php: -------------------------------------------------------------------------------- 1 | var = $arr; 21 | } 22 | } 23 | 24 | public function rewind() 25 | { 26 | reset($this->var); 27 | } 28 | 29 | public function current() 30 | { 31 | return current($this->var); 32 | } 33 | 34 | public function key() 35 | { 36 | return key($this->var); 37 | } 38 | 39 | public function next() 40 | { 41 | return next($this->var); 42 | } 43 | 44 | public function valid() 45 | { 46 | return $this->current() !== false; 47 | } 48 | } 49 | 50 | $it = new IteratorDemo([1, 2, 3]); 51 | dump($it); 52 | 53 | foreach ($it as $k => $item) { 54 | dump("$k:$item"); 55 | } -------------------------------------------------------------------------------- /php/Demo/Old/IteratorDemo2.php: -------------------------------------------------------------------------------- 1 | var = $arr; 22 | } 23 | } 24 | 25 | public function rewind() 26 | { 27 | $this->n = 0; 28 | } 29 | 30 | public function current() 31 | { 32 | return $this->var[$this->n]; 33 | } 34 | 35 | public function key() 36 | { 37 | return $this->n; 38 | } 39 | 40 | public function next() 41 | { 42 | return $this->n++; 43 | } 44 | 45 | public function valid() 46 | { 47 | return isset($this->var[$this->n]); 48 | } 49 | } 50 | 51 | $it = new IteratorDemo([1, 2, 3]); 52 | dump($it); 53 | 54 | foreach ($it as $k => $item) { 55 | dump("$k:$item"); 56 | } -------------------------------------------------------------------------------- /php/Demo/Old/Read.php: -------------------------------------------------------------------------------- 1 | = 0) { 25 | throw new \LogicException('Step must be -ve'); 26 | } 27 | 28 | for ($i = $start; $i >= $limit; $i += $step) { 29 | yield $i; 30 | } 31 | } 32 | } 33 | 34 | dump($a = memory_get_usage()); //533824 35 | $n1 = range(0, N); 36 | dump($b = memory_get_usage(), $b - $a); //34440680 33906552 32mb 37 | $n2 = xRange(0, N); 38 | dump(memory_get_usage() - $b); // 768 bytes 39 | 40 | function count_num() 41 | { 42 | yield from [10, 2, 3]; 43 | } 44 | 45 | foreach (count_num() as $item) { 46 | dump($item); 47 | } 48 | -------------------------------------------------------------------------------- /php/Demo/Old/regex.php: -------------------------------------------------------------------------------- 1 | container = []; 18 | } 19 | 20 | public function add($value) 21 | { 22 | $this->container = array_merge($this->container, $value); 23 | } 24 | 25 | 26 | public function offsetSet($offset, $value) 27 | { 28 | if (is_null($offset)) { 29 | $this->container[] = $value; 30 | } else { 31 | $this->container[$offset] = $value; 32 | } 33 | } 34 | 35 | public function offsetGet($offset) 36 | { 37 | return $this->container[$offset] ?? null; 38 | } 39 | 40 | public function offsetExists($offset) 41 | { 42 | return isset($this->container[$offset]); 43 | } 44 | 45 | public function offsetUnset($offset) 46 | { 47 | unset($this->container[$offset]); 48 | } 49 | } -------------------------------------------------------------------------------- /php/Demo/PredefinedInterfaces/MyIterator.php: -------------------------------------------------------------------------------- 1 | pos = 0; 19 | } 20 | 21 | public function add($value) 22 | { 23 | $this->arr[] = $value; 24 | } 25 | 26 | public function rewind() 27 | { 28 | $this->pos = 0; 29 | } 30 | 31 | public function current() 32 | { 33 | return $this->arr[$this->pos]; 34 | } 35 | 36 | public function next() 37 | { 38 | $this->pos++; 39 | } 40 | 41 | public function key() 42 | { 43 | return $this->pos; 44 | } 45 | 46 | public function valid() 47 | { 48 | return isset($this->arr[$this->pos]); 49 | } 50 | } -------------------------------------------------------------------------------- /php/Demo/PredefinedInterfaces/MyIteratorAggregate.php: -------------------------------------------------------------------------------- 1 | property4 = 'four'; 19 | } 20 | 21 | public function getIterator() 22 | { 23 | return new \ArrayIterator($this); 24 | } 25 | } -------------------------------------------------------------------------------- /php/Demo/PredefinedInterfaces/MySerializable.php: -------------------------------------------------------------------------------- 1 | serialized = ''; 19 | } 20 | 21 | public function add($value) 22 | { 23 | $this->serialized = $value; 24 | } 25 | 26 | public function __wakeup() 27 | { 28 | return '序列化'; 29 | } 30 | 31 | public function __sleep() 32 | { 33 | return '反序列化'; 34 | } 35 | 36 | public function serialize() 37 | { 38 | return serialize($this->serialized); 39 | } 40 | 41 | public function unserialize($serialized) 42 | { 43 | $this->serialized = unserialize($serialized); 44 | } 45 | 46 | public function getData() 47 | { 48 | return $this->serialized; 49 | } 50 | 51 | } -------------------------------------------------------------------------------- /php/Demo/PredefinedInterfaces/MyTraversable.php: -------------------------------------------------------------------------------- 1 | channel(); 15 | 16 | $channel->exchange_declare('logs', 'fanout', false, false, false); 17 | 18 | $data = implode(' ', array_slice($argv, 1)); 19 | if (empty($data)) { 20 | $data = "info: Hello World!"; 21 | } 22 | $msg = new AMQPMessage($data); 23 | 24 | $channel->basic_publish($msg, 'logs'); 25 | 26 | echo ' [x] Sent ', $data, "\n"; 27 | 28 | $channel->close(); 29 | $connection->close(); -------------------------------------------------------------------------------- /php/Demo/RabbitMQ/emit_log_direct.php: -------------------------------------------------------------------------------- 1 | channel(); 14 | 15 | $channel->exchange_declare('direct_logs', 'direct', false, false, false); 16 | 17 | $severity = isset($argv[1]) && !empty($argv[1]) ? $argv[1] : 'info'; 18 | 19 | $data = implode(' ', array_slice($argv, 2)); 20 | if (empty($data)) { 21 | $data = "Hello World!"; 22 | } 23 | 24 | $msg = new AMQPMessage($data); 25 | 26 | $channel->basic_publish($msg, 'direct_logs', $severity); 27 | 28 | echo ' [x] Sent ', $severity, ':', $data, "\n"; 29 | 30 | $channel->close(); 31 | $connection->close(); -------------------------------------------------------------------------------- /php/Demo/RabbitMQ/emit_log_topic.php: -------------------------------------------------------------------------------- 1 | channel(); 14 | 15 | // php emit_log_topic.php "kern.critical" "A critical kernel error" 16 | $channel->exchange_declare('topic_logs', 'topic', false, false, false); 17 | 18 | $routing_key = isset($argv[1]) && !empty($argv[1]) ? $argv[1] : 'anonymous.info'; 19 | $data = implode(' ', array_slice($argv, 2)); 20 | if (empty($data)) { 21 | $data = "Hello World!"; 22 | } 23 | 24 | $msg = new AMQPMessage($data); 25 | 26 | $channel->basic_publish($msg, 'topic_logs', $routing_key); 27 | 28 | echo ' [x] Sent ', $routing_key, ':', $data, "\n"; 29 | 30 | $channel->close(); 31 | $connection->close(); -------------------------------------------------------------------------------- /php/Demo/RabbitMQ/new_task.php: -------------------------------------------------------------------------------- 1 | channel(); 17 | $channel->queue_declare('hello', false, false, false, false); 18 | 19 | $data = implode(' ', array_slice($argv, 1)); 20 | if (empty($data)) { 21 | $data = "Hello World!"; 22 | } 23 | $msg = new AMQPMessage($data); 24 | 25 | $channel->basic_publish($msg, '', 'hello'); 26 | 27 | echo ' [x] Sent ', $data, "\n"; 28 | 29 | $channel->close(); 30 | $connection->close(); -------------------------------------------------------------------------------- /php/Demo/RabbitMQ/new_task2.php: -------------------------------------------------------------------------------- 1 | channel(); 17 | $channel->queue_declare('task_queue', false, true, false, false); 18 | 19 | $data = implode(' ', array_slice($argv, 1)); 20 | if (empty($data)) { 21 | $data = "Hello World!"; 22 | } 23 | $msg = new AMQPMessage( 24 | $data, 25 | ['delivery_mode' => AMQPMessage::DELIVERY_MODE_PERSISTENT] 26 | ); 27 | 28 | $channel->basic_publish($msg, '', 'hello'); 29 | 30 | echo ' [x] Sent ', $data, "\n"; 31 | 32 | $channel->close(); 33 | $connection->close(); -------------------------------------------------------------------------------- /php/Demo/RabbitMQ/receive.php: -------------------------------------------------------------------------------- 1 | channel(); 15 | $channel->queue_declare('hello', false, false, false, false); 16 | echo " [*] Waiting for messages. To exit press CTRL+C\n"; 17 | $callback = function ($msg) { 18 | echo ' [x] Received ', $msg->body, "\n"; 19 | }; 20 | $channel->basic_consume('hello', '', false, true, false, false, $callback); 21 | while (count($channel->callbacks)) { 22 | $channel->wait(); 23 | } 24 | $channel->close(); 25 | $connection->close(); -------------------------------------------------------------------------------- /php/Demo/RabbitMQ/receive_logs.php: -------------------------------------------------------------------------------- 1 | channel(); 14 | 15 | $channel->exchange_declare('logs', 'fanout', false, false, false); 16 | 17 | [$queue_name, ,] = $channel->queue_declare("", false, false, true, false); 18 | 19 | $channel->queue_bind($queue_name, 'logs'); 20 | 21 | echo " [*] Waiting for logs. To exit press CTRL+C\n"; 22 | 23 | $callback = function ($msg) { 24 | echo ' [x] ', $msg->body, "\n"; 25 | }; 26 | 27 | $channel->basic_consume($queue_name, '', false, true, false, false, $callback); 28 | 29 | while (count($channel->callbacks)) { 30 | $channel->wait(); 31 | } 32 | 33 | $channel->close(); 34 | $connection->close(); -------------------------------------------------------------------------------- /php/Demo/RabbitMQ/receive_logs_direct.php: -------------------------------------------------------------------------------- 1 | channel(); 14 | 15 | $channel->exchange_declare('direct_logs', 'direct', false, false, false); 16 | 17 | [$queue_name, ,] = $channel->queue_declare("", false, false, true, false); 18 | 19 | $severities = array_slice($argv, 1); 20 | if (empty($severities)) { 21 | file_put_contents('php://stderr', "Usage: $argv[0] [info] [warning] [error]\n"); 22 | exit(1); 23 | } 24 | 25 | foreach ($severities as $severity) { 26 | $channel->queue_bind($queue_name, 'direct_logs', $severity); 27 | } 28 | 29 | echo " [*] Waiting for logs. To exit press CTRL+C\n"; 30 | 31 | $callback = function ($msg) { 32 | echo ' [x] ', $msg->delivery_info['routing_key'], ':', $msg->body, "\n"; 33 | }; 34 | 35 | $channel->basic_consume($queue_name, '', false, true, false, false, $callback); 36 | 37 | while (count($channel->callbacks)) { 38 | $channel->wait(); 39 | } 40 | 41 | $channel->close(); 42 | $connection->close(); -------------------------------------------------------------------------------- /php/Demo/RabbitMQ/receive_logs_topic.php: -------------------------------------------------------------------------------- 1 | channel(); 14 | 15 | // php receive_logs_topic.php "kern.*" "*.critical" 16 | // 使用#等效于fanout 所有都监听 17 | // 使用*等效于direct 符合模式的才监听 18 | $channel->exchange_declare('topic_logs', 'topic', false, false, false); 19 | 20 | [$queue_name, ,] = $channel->queue_declare("", false, false, true, false); 21 | 22 | $binding_keys = array_slice($argv, 1); 23 | if (empty($binding_keys)) { 24 | file_put_contents('php://stderr', "Usage: $argv[0] [binding_key]\n"); 25 | exit(1); 26 | } 27 | 28 | foreach ($binding_keys as $binding_key) { 29 | $channel->queue_bind($queue_name, 'topic_logs', $binding_key); 30 | } 31 | 32 | echo " [*] Waiting for logs. To exit press CTRL+C\n"; 33 | 34 | $callback = function ($msg) { 35 | echo ' [x] ', $msg->delivery_info['routing_key'], ':', $msg->body, "\n"; 36 | }; 37 | 38 | $channel->basic_consume($queue_name, '', false, true, false, false, $callback); 39 | 40 | while (count($channel->callbacks)) { 41 | $channel->wait(); 42 | } 43 | 44 | $channel->close(); 45 | $connection->close(); -------------------------------------------------------------------------------- /php/Demo/RabbitMQ/rpc_client.php: -------------------------------------------------------------------------------- 1 | connection = new AMQPStreamConnection( 23 | 'localhost', 24 | 5672, 25 | 'guest', 26 | 'guest' 27 | ); 28 | $this->channel = $this->connection->channel(); 29 | list($this->callback_queue, ,) = $this->channel->queue_declare( 30 | "", 31 | false, 32 | false, 33 | true, 34 | false 35 | ); 36 | $this->channel->basic_consume( 37 | $this->callback_queue, 38 | '', 39 | false, 40 | false, 41 | false, 42 | false, 43 | array( 44 | $this, 45 | 'onResponse' 46 | ) 47 | ); 48 | } 49 | 50 | public function onResponse($rep) 51 | { 52 | if ($rep->get('correlation_id') == $this->corr_id) { 53 | $this->response = $rep->body; 54 | } 55 | } 56 | 57 | public function call($n) 58 | { 59 | $this->response = null; 60 | $this->corr_id = uniqid(); 61 | 62 | $msg = new AMQPMessage( 63 | (string) $n, 64 | array( 65 | 'correlation_id' => $this->corr_id, 66 | 'reply_to' => $this->callback_queue 67 | ) 68 | ); 69 | $this->channel->basic_publish($msg, '', 'rpc_queue'); 70 | while (!$this->response) { 71 | $this->channel->wait(); 72 | } 73 | return intval($this->response); 74 | } 75 | } 76 | 77 | $fibonacci_rpc = new FibonacciRpcClient(); 78 | $response = $fibonacci_rpc->call(30); 79 | echo ' [.] Got ', $response, "\n"; -------------------------------------------------------------------------------- /php/Demo/RabbitMQ/rpc_server.php: -------------------------------------------------------------------------------- 1 | channel(); 14 | 15 | $channel->queue_declare('rpc_queue', false, false, false, false); 16 | 17 | function fib($n) 18 | { 19 | if ($n == 0) { 20 | return 0; 21 | } 22 | if ($n == 1) { 23 | return 1; 24 | } 25 | return fib($n-1) + fib($n-2); 26 | } 27 | 28 | echo " [x] Awaiting RPC requests\n"; 29 | $callback = function ($req) { 30 | $n = intval($req->body); 31 | echo ' [.] fib(', $n, ")\n"; 32 | 33 | $msg = new AMQPMessage( 34 | (string) fib($n), 35 | array('correlation_id' => $req->get('correlation_id')) 36 | ); 37 | 38 | $req->delivery_info['channel']->basic_publish( 39 | $msg, 40 | '', 41 | $req->get('reply_to') 42 | ); 43 | $req->delivery_info['channel']->basic_ack( 44 | $req->delivery_info['delivery_tag'] 45 | ); 46 | }; 47 | 48 | $channel->basic_qos(null, 1, null); 49 | $channel->basic_consume('rpc_queue', '', false, false, false, false, $callback); 50 | 51 | while (count($channel->callbacks)) { 52 | $channel->wait(); 53 | } 54 | 55 | $channel->close(); 56 | $connection->close(); -------------------------------------------------------------------------------- /php/Demo/RabbitMQ/send.php: -------------------------------------------------------------------------------- 1 | channel(); 16 | $channel->queue_declare('hello', false, false, false, false); 17 | $msg = new AMQPMessage('Hello World!'); 18 | $channel->basic_publish($msg, '', 'hello'); 19 | echo " [x] Sent 'Hello World!'\n"; 20 | $channel->close(); 21 | $connection->close(); -------------------------------------------------------------------------------- /php/Demo/RabbitMQ/worker.php: -------------------------------------------------------------------------------- 1 | channel(); 14 | $channel->queue_declare('hello', false, false, false, false); 15 | echo " [*] Waiting for messages. To exit press CTRL+C\n"; 16 | 17 | $callback = function ($msg) { 18 | echo ' [x] Received ', $msg->body, "\n"; 19 | sleep(substr_count($msg->body, '.')); 20 | echo " [x] Done\n"; 21 | $msg->delivery_info['channel']->basic_ack($msg->delivery_info['delivery_tag']); 22 | }; 23 | 24 | $channel->basic_consume('hello', '', false, false, false, false, $callback); 25 | 26 | while (count($channel->callbacks)) { 27 | $channel->wait(); 28 | } 29 | $channel->close(); 30 | $connection->close(); -------------------------------------------------------------------------------- /php/Demo/RabbitMQ/worker2.php: -------------------------------------------------------------------------------- 1 | channel(); 14 | // 持久化 15 | $channel->queue_declare('task_queue', false, true, false, false); 16 | echo " [*] Waiting for messages. To exit press CTRL+C\n"; 17 | 18 | $callback = function ($msg) { 19 | echo ' [x] Received ', $msg->body, "\n"; 20 | sleep(substr_count($msg->body, '.')); 21 | echo " [x] Done\n"; 22 | $msg->delivery_info['channel']->basic_ack($msg->delivery_info['delivery_tag']); 23 | }; 24 | 25 | // 公平派遣 26 | $channel->basic_qos(null, 1, null); 27 | $channel->basic_consume('hello', '', false, false, false, false, $callback); 28 | 29 | while (count($channel->callbacks)) { 30 | $channel->wait(); 31 | } 32 | $channel->close(); 33 | $connection->close(); -------------------------------------------------------------------------------- /php/Demo/Spider/ZiZhuZhang.php: -------------------------------------------------------------------------------- 1 | totalPageCount = count($this->users); 26 | $client = new Client(); 27 | $requests = function ($total) use ($client) { 28 | foreach ($this->users as $user) { 29 | $uri = 'https://api.github.com/users/' . $user; 30 | yield function () use ($client, $uri) { 31 | return $client->getAsync($uri); 32 | }; 33 | } 34 | }; 35 | 36 | $pool = new Pool($client, $requests($this->totalPageCount), [ 37 | 'concurrency' => $this->concurrency, 38 | 'fulfilled' => function ($response, $index) { 39 | $res = json_decode($response->getBody()->getContents()); 40 | dump("请求第 $index 个请求,用户 " . $this->users[$index] . " 的 Github ID 为:" . $res->id); 41 | $this->countedAndCheckEnded(); 42 | }, 43 | 'rejected' => function ($reason, $index) { 44 | dump("rejected"); 45 | dump("rejected reason: " . $reason); 46 | $this->countedAndCheckEnded(); 47 | }, 48 | ]); 49 | 50 | // 开始发送请求 51 | $promise = $pool->promise(); 52 | $promise->wait(); 53 | } 54 | 55 | public function countedAndCheckEnded() 56 | { 57 | if ($this->counter < $this->totalPageCount) { 58 | $this->counter++; 59 | return; 60 | } 61 | dd("请求结束!"); 62 | } 63 | } -------------------------------------------------------------------------------- /php/Demo/Tools/generate.php: -------------------------------------------------------------------------------- 1 | #!/usr/local/opt/php/bin/php 2 | $value) { 49 | if ($k == 1000) dump($value); 50 | } 51 | -------------------------------------------------------------------------------- /php/Demo/Tools/preg.php: -------------------------------------------------------------------------------- 1 | ZBD11674ZBF11179 12 | XML; 13 | 14 | $pattern = '/.*?<\/Equipment>/'; 15 | 16 | preg_match_all($pattern, $str, $match); 17 | 18 | dump($match); -------------------------------------------------------------------------------- /php/Ext/Date/index.php: -------------------------------------------------------------------------------- 1 | cal(); 18 | $this->dateTime(); 19 | $this->func(); 20 | echo "------------------------------- ExtDate ---------------------------------\n"; 21 | } 22 | 23 | public function cal(): void 24 | { 25 | echo "------------------------------- cal ---------------------------------\n"; 26 | dump(cal_days_in_month(0, 12, 2017)); 27 | } 28 | 29 | public function dateTime(): void 30 | { 31 | echo "------------------------------- dateTime ---------------------------------\n"; 32 | $date = new \DateTime(); 33 | $now = $date->format(static::FORMAT); 34 | $now_modify = $date->modify('+30 days')->format(static::FORMAT); 35 | dump($now); 36 | dump($now_modify); 37 | 38 | $now = date_create($now); 39 | $now_modify = date_create($now_modify); 40 | dump(date_diff($now,$now_modify)->format('%R%a days')); 41 | 42 | dump($date->getTimestamp()); 43 | dump($date->getTimezone()->getName()); 44 | } 45 | 46 | public function func() 47 | { 48 | echo "------------------------------- func ---------------------------------\n"; 49 | dump(date_default_timezone_get()); 50 | date_default_timezone_set('PRC'); 51 | 52 | dump(checkdate(13,30,2017)); 53 | dump(checkdate(12,31,2017)); 54 | 55 | dump(microtime(true)); 56 | 57 | dump(mktime(0,0,0,12,12,2017)); 58 | dump(time()); 59 | dump(getdate()); 60 | dump(date('Y-m-d H:i:s',time())); 61 | dump(strtotime((new \DateTime())->format(static::FORMAT))); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /php/Ext/Dom/book.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | My lists 4 | 5 | My books 6 | 7 | 8 | 9 | 10 | 11 | 标题 12 | 作者 13 | 语言 14 | ISBN 15 | 16 | 17 | 18 | 19 | The Grapes of Wrath 20 | John Steinbeck 21 | en 22 | 0140186409 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /php/Ext/Dom/index.php: -------------------------------------------------------------------------------- 1 | xml(); 17 | $this->createXmlByDom(); 18 | $this->createXmlBySimple(); 19 | echo "------------------------------- ExtDom ---------------------------------\n"; 20 | } 21 | 22 | public function xml() 23 | { 24 | echo "------------------------------- xml ---------------------------------\n"; 25 | $xml = new \DOMDocument('1.0', 'utf-8'); 26 | 27 | // $xml->validateOnParse = true; 28 | 29 | $xml->load(__DIR__ . '/book.xml'); 30 | 31 | dump($xml->saveXML()); 32 | 33 | $books = $xml->getElementsByTagName('row'); 34 | foreach ($books as $book) { 35 | dump($book->nodeValue); 36 | } 37 | 38 | dump($books->item(1)->nodeValue); 39 | 40 | // dump($xml->getElementById('books')->tagName); 41 | } 42 | 43 | public function createXmlByDom() 44 | { 45 | echo "------------------------------- createXmlByDom ---------------------------------\n"; 46 | //创建xml文档对象 47 | $dom = new \DomDocument('1.0','utf-8'); 48 | //创建根元素节点 49 | $root = $dom->createElement("root"); 50 | //将根元素节点添加到文档对象中 51 | $dom->appendChild($root); 52 | //为根元素节点创建属性节点 53 | $name_attr = $dom->createAttribute('name'); 54 | //创建属性值 55 | $attr_val = $dom->createTextNode('落花流水'); 56 | //将文本节点添加到属性元素节点上 57 | $name_attr->appendChild($attr_val); 58 | //将属性节点添加到根元素节点当中 59 | $root->appendChild($name_attr); 60 | //创建文本节点 61 | $text = $dom->createTextNode("你无情"); 62 | //将文本节点添加到父元素节点上 63 | $root->appendChild($text); 64 | //保存显示 65 | dump($dom->saveXML()); 66 | } 67 | 68 | public function createXmlBySimple() 69 | { 70 | echo "------------------------------- createXmlBySimple ---------------------------------\n"; 71 | $xml = << 73 | 74 | 75 | EOT; 76 | 77 | //创建一个新的SimpleXMLElement对象 其中$xml参数可是字符串也可以是url 78 | $xml = new \SimpleXMLElement($xml); 79 | //通过addChild函数向指定节点中添加一个子节点,返回一个子节点的对象 80 | $name = $xml->addChild('name', '落花流水'); 81 | //向name节点中添加属性节点 82 | $name->addAttribute('type', 'aa'); 83 | //再次向父节点中添加子节点 84 | $xml->addChild('age', 24); 85 | //向父节点中添加性别节点 86 | $sex = $xml->addChild('sex', '男'); 87 | //在性别节点中设置属性 88 | $sex->addAttribute('att', 'img'); 89 | 90 | //获取元素的值和元素的名称 91 | foreach ($xml->children() as $child) { 92 | dump($child->getName()); 93 | } 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /php/Ext/Exif/P71005-185741.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OMGZui/noteBook/19d48d912e5e07271b370dbe00e498e5f18a29e7/php/Ext/Exif/P71005-185741.jpg -------------------------------------------------------------------------------- /php/Ext/Exif/index.php: -------------------------------------------------------------------------------- 1 | read(); 17 | echo "------------------------------- ExtExif ---------------------------------\n"; 18 | } 19 | 20 | //JPEG,TIFF 21 | public function read() 22 | { 23 | $exif = exif_read_data(__DIR__.'/P71005-185741.jpg',0,true); 24 | 25 | dump($exif); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /php/Level/l/big.txt: -------------------------------------------------------------------------------- 1 | 1111111111 2 | 2222222222 3 | 3333333333 4 | 4444444444 5 | -------------------------------------------------------------------------------- /php/Level/l/big1.txt: -------------------------------------------------------------------------------- 1 | 1111111111 2 | 2222222222 3 | 3333333333 4 | 4444444444 5 | 5555555555 -------------------------------------------------------------------------------- /php/Level/l/big2.txt: -------------------------------------------------------------------------------- 1 | 1111111111 2 | 2222222222 3 | 3333333333 4 | 4444444444 5 | 5555535555 -------------------------------------------------------------------------------- /php/Level/l1.php: -------------------------------------------------------------------------------- 1 | rewind(); 25 | $file2->rewind(); 26 | while ($file1->valid() && $file2->valid()) { 27 | if ($file1->current() == $file2->current()) { 28 | file_put_contents('./l/big.txt', $file1->current(), FILE_APPEND); 29 | } 30 | $file1->next(); 31 | $file2->next(); 32 | } 33 | 34 | // 自己实现一个支持回调的PHP函数 35 | // 思路:主要是回调函数callback 36 | function myCallBack(Closure $closure, $a, $b) 37 | { 38 | return $closure($a, $b); 39 | } 40 | 41 | dump(myCallBack(function ($a, $b) { 42 | return $a + $b; 43 | }, 1, 2)); 44 | 45 | // 请写出至少两个获取指定文件夹下所有文件的方法(代码或思路)。 46 | // 思路:递归获取,排除.和..,除了文件夹就是文件 47 | function myScanDir($dir) 48 | { 49 | $files = array(); 50 | if (is_dir($dir)) { 51 | if ($handle = opendir($dir)) { 52 | while (($file = readdir($handle)) !== false) { 53 | if ($file != "." && $file != "..") { 54 | if (is_dir($dir . "/" . $file)) { 55 | $files[$file] = myScanDir($dir . "/" . $file); 56 | } else { 57 | $files[] = $dir . "/" . $file; 58 | } 59 | } 60 | } 61 | closedir($handle); 62 | return $files; 63 | } 64 | } 65 | } 66 | dump(myScanDir('.')); 67 | 68 | // [0,1,2,3] + [1,2,3,4,5] = [0,1,2,3,5] 联合 69 | -------------------------------------------------------------------------------- /php/Level/sort.php: -------------------------------------------------------------------------------- 1 | 0; $i--) { //外层循环控制轮次 43 | for ($j = 0; $j < $i; $j++) { //内层循环进行比较 44 | if ($arr[$i] < $arr[$j]) { //比较,大的一直是$arr[$j],也就是后者 45 | [$arr[$i], $arr[$j]] = [$arr[$j], $arr[$i]]; 46 | } 47 | } //一轮下来最大值在末尾 48 | }//n轮下来排序完成,时间复杂度O(n^2) 49 | return $arr; //优化思路:添加一个标记,如果一趟遍历中发生了交换,则标记为true,否则为false。如果某一趟没有发生交换,说明排序已经完成! 50 | } 51 | 52 | bubble_sort($arr); 53 | $t2 = microtime(true); 54 | //dump(bubble_sort($arr)); 55 | dump(($t2 - $t1) * 1000 . 'ms'); 56 | 57 | // 快速排序 58 | $t1 = microtime(true); 59 | /** 60 | * 快速排序 61 | * 62 | * 选择一个基准数 63 | * 通过一趟排序将要排序的数据分割成独立的两部分 64 | * 其中一部分的所有数据都比另外一部分的所有数据都要小 65 | * 然后,再按此方法对这两部分数据分别进行快速排序 66 | * 整个排序过程可以递归进行,以此达到整个数据变成有序序列。 67 | * 68 | * @param $arr 69 | * @return array 70 | */ 71 | function quick_sort($arr) 72 | { 73 | $len = count($arr); //长度 74 | if ($len <= 1) { //只剩一个元素,直接返回 75 | return $arr; 76 | } 77 | 78 | $base = $arr[0]; //基准数 79 | $left = []; //初始化左边 80 | $right = []; //初始化右边 81 | 82 | for ($i = 1; $i < $len; $i++) { //轮次 83 | if ($arr[$i] < $base) { //小于基准数的放入左边 84 | $left[] = $arr[$i]; 85 | } else { //大于基准数的放入右边 86 | $right[] = $arr[$i]; 87 | } 88 | } 89 | 90 | $left = quick_sort($left); //递归左边 91 | $right = quick_sort($right); //递归右边 92 | 93 | return array_merge($left, [$base], $right); //合并左边、基准数、右边,完成排序 94 | } 95 | 96 | quick_sort($arr); 97 | $t2 = microtime(true); 98 | //dump(quick_sort($arr)); 99 | dump(($t2 - $t1) * 1000 . 'ms'); 100 | 101 | // 插入排序 102 | $t1 = microtime(true); 103 | /** 104 | * 插入排序 105 | * 106 | * 把n个待排序的元素看成为一个有序表和一个无序表 107 | * 开始时有序表中只包含1个元素,无序表中包含有n-1个元素 108 | * 排序过程中每次从无序表中取出第一个元素,将它插入到有序表中的适当位置,使之成为新的有序表,重复n-1次可完成排序过程 109 | * 110 | * @param $arr 111 | * @return array 112 | */ 113 | function insert_sort($arr) 114 | { 115 | $len = count($arr); //长度 116 | for ($i = 1; $i < $len; $i++) { //无序轮次 117 | $temp = $arr[$i]; //拿出一个临时元素 118 | for ($j = $i - 1; $j >= 0; $j--) { //有序轮次 119 | if ($temp < $arr[$j]) { // 将临时元素放入有序位置 120 | $arr[$j + 1] = $arr[$j]; 121 | $arr[$j] = $temp; 122 | } 123 | } 124 | } 125 | return $arr; 126 | } 127 | 128 | insert_sort($arr); 129 | $t2 = microtime(true); 130 | //dump(insert_sort($arr)); 131 | dump(($t2 - $t1) * 1000 . 'ms'); 132 | 133 | // 选择排序 134 | $t1 = microtime(true); 135 | /** 136 | * 选择排序 137 | * 138 | * 首先在未排序的数列中找到最小(or最大)元素, 139 | * 然后将其存放到数列的起始位置; 140 | * 接着,再从剩余未排序的元素中继续寻找最小(or最大)元素, 141 | * 然后放到已排序序列的末尾。 142 | * 以此类推,直到所有元素均排序完毕。 143 | * @param $arr 144 | * @return mixed 145 | */ 146 | function select_sort($arr) 147 | { 148 | $len = count($arr); //长度 149 | for ($i = 0; $i < $len - 1; $i++) { //轮次 150 | $min = $i; //假定的最小值 151 | for ($j = $i + 1; $j < $len; $j++) { //比较轮次 152 | if ($arr[$min] > $arr[$j]) { 153 | $min = $j; 154 | } 155 | } 156 | if ($min != $i) { //选出最小值 157 | [$arr[$min], $arr[$i]] = [$arr[$i], $arr[$min]]; 158 | } 159 | } 160 | return $arr; //相当于每次把最小值放入$arr[$i]的位置 161 | } 162 | 163 | select_sort($arr); 164 | $t2 = microtime(true); 165 | //dump(select_sort($arr)); 166 | dump(($t2 - $t1) * 1000 . 'ms'); 167 | 168 | 169 | // "2930.732011795ms" 170 | // "13.242959976196ms" 171 | // "2146.6610431671ms" 172 | // "1665.9348011017ms" 173 | 174 | 175 | // 冒泡排序、插入排序、选择排序时间复杂度都是O(n^2) 176 | // 快速排序最坏情况下是O(n^2),平均的时间复杂度是O(n*lgn) 177 | // 可以看出快速排序是速度最快的,选择排序其次,冒泡排序和插入排序差不多 178 | 179 | 180 | # 参考动图 https://visualgo.net/en/sorting 181 | -------------------------------------------------------------------------------- /php/bootstrap.php: -------------------------------------------------------------------------------- 1 | resolving(function ($object, $app) { 20 | dump($object); 21 | // dump($app); 22 | }); 23 | 24 | // 简单绑定 25 | // alias绑定 26 | $container->bind('hello1', Hello::class); 27 | $container->bind('hello2', function () { 28 | return new Hello(); 29 | }); 30 | // 接口绑定 31 | $container->bind( 32 | HelloInterface::class, 33 | Hello::class, 34 | true 35 | ); 36 | // 单例绑定 37 | $container->singleton( 38 | HelloInterface::class, 39 | Hello::class 40 | ); 41 | // 实例绑定 42 | $container->instance('hello4', new Hello()); 43 | dump($container); 44 | // 解析 45 | $hello1 = $container->make('hello1'); 46 | $hello2 = $container->make('hello2'); 47 | $hello3 = $container->make(Hello::class); 48 | $hello4 = $container->make('hello4'); 49 | //dump($hello1); 50 | //dump($hello2); 51 | //dump($hello3); 52 | //dump($hello4); 53 | dump($container); 54 | 55 | 56 | -------------------------------------------------------------------------------- /php/container/src/hello.php: -------------------------------------------------------------------------------- 1 | 4 | 5 | - [Facade 门面](#facade-门面) 6 | - [一、问题](#一问题) 7 | - [二、原理](#二原理) 8 | - [三、别名Aliases](#三别名aliases) 9 | - [四、启动Aliases](#四启动aliases) 10 | 11 | 12 | 13 | 前言:Facade到底是如何实现的 14 | 15 | ## 一、问题 16 | 17 | 我们经常看到 18 | 19 | ```php 20 | Route::get('/', function () { 21 | return view('welcome'); 22 | }); 23 | ``` 24 | 25 | 其实就是等价于 26 | 27 | ```php 28 | app('router')->get('/', function () { 29 | return view('welcome'); 30 | }); 31 | // 本质 32 | \Illuminate\Container\Container::getInstance()->make('router')->get('/', function () { 33 | return view('welcome'); 34 | }); 35 | ``` 36 | 37 | ## 二、原理 38 | 39 | 比如Route 40 | 41 | ```php 42 | // vendor/laravel/framework/src/Illuminate/Support/Facades/Route.php 43 | class Route extends Facade 44 | { 45 | protected static function getFacadeAccessor() 46 | { 47 | return 'router'; 48 | } 49 | } 50 | 51 | // vendor/laravel/framework/src/Illuminate/Support/Facades/Facade.php 52 | abstract class Facade 53 | { 54 | // 在容器中解析出'router'实例 55 | protected static function resolveFacadeInstance($name) 56 | { 57 | if (is_object($name)) { 58 | return $name; 59 | } 60 | 61 | if (isset(static::$resolvedInstance[$name])) { 62 | return static::$resolvedInstance[$name]; 63 | } 64 | 65 | return static::$resolvedInstance[$name] = static::$app[$name]; 66 | } 67 | 68 | // 拿到门面'router' 69 | public static function getFacadeRoot() 70 | { 71 | return static::resolveFacadeInstance(static::getFacadeAccessor()); 72 | } 73 | 74 | // 魔术方法返回 75 | public static function __callStatic($method, $args) 76 | { 77 | $instance = static::getFacadeRoot(); 78 | 79 | if (! $instance) { 80 | throw new RuntimeException('A facade root has not been set.'); 81 | } 82 | 83 | return $instance->$method(...$args); 84 | } 85 | } 86 | 87 | ``` 88 | 89 | 我们为什么可以直接`Route::get()`呢,是因为Facade里的魔术方法`__callStatic()`,可以动态的处理一系列静态函数。 90 | 91 | ## 三、别名Aliases 92 | 93 | 主要是用了函数`class_alias()(为一个类创建别名)` 94 | 95 | ```php 96 | // config/app.php 97 | 'aliases' => [ 98 | 'Route' => Illuminate\Support\Facades\Route::class, 99 | ] 100 | ``` 101 | 102 | ## 四、启动Aliases 103 | 104 | ```php 105 | // public/index.php 106 | // composer自动加载 107 | require __DIR__.'/../vendor/autoload.php'; 108 | // 获取IOC容器 109 | $app = require_once __DIR__.'/../bootstrap/app.php'; 110 | // 制造出http请求内核 111 | $kernel = $app->make(Illuminate\Contracts\Http\Kernel::class); 112 | // laravel里面所有功能服务的注册加载,乃至Http请求的构造与传递都是这一句的功劳。 113 | $response = $kernel->handle( 114 | $request = Illuminate\Http\Request::capture() 115 | ); 116 | 117 | // vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php 118 | class Kernel implements KernelContract 119 | { 120 | protected $bootstrappers = [ 121 | \Illuminate\Foundation\Bootstrap\RegisterFacades::class, 122 | ]; 123 | 124 | // 处理http请求 125 | public function handle($request) 126 | { 127 | $response = $this->sendRequestThroughRouter($request); 128 | } 129 | 130 | protected function sendRequestThroughRouter($request) 131 | { 132 | $this->app->instance('request', $request); 133 | 134 | Facade::clearResolvedInstance('request'); 135 | 136 | $this->bootstrap(); 137 | 138 | return (new Pipeline($this->app)) 139 | ->send($request) 140 | ->through($this->app->shouldSkipMiddleware() ? [] : $this->middleware) 141 | ->then($this->dispatchToRouter()); 142 | } 143 | 144 | public function bootstrap() 145 | { 146 | if (! $this->app->hasBeenBootstrapped()) { 147 | $this->app->bootstrapWith($this->bootstrappers()); 148 | } 149 | } 150 | } 151 | 152 | // vendor/laravel/framework/src/Illuminate/Foundation/Application.php 153 | class Application extends Container implements ApplicationContract, HttpKernelInterface 154 | { 155 | // 利用组件进行启动服务 156 | public function bootstrapWith(array $bootstrappers) 157 | { 158 | $this->hasBeenBootstrapped = true; 159 | 160 | foreach ($bootstrappers as $bootstrapper) { 161 | $this['events']->dispatch('bootstrapping: '.$bootstrapper, [$this]); 162 | 163 | $this->make($bootstrapper)->bootstrap($this); 164 | 165 | $this['events']->dispatch('bootstrapped: '.$bootstrapper, [$this]); 166 | } 167 | } 168 | } 169 | // vendor/laravel/framework/src/Illuminate/Foundation/Bootstrap/RegisterFacades.php 170 | class RegisterFacades 171 | { 172 | public function bootstrap(Application $app) 173 | { 174 | // 清除Facade缓存实例 175 | Facade::clearResolvedInstances(); 176 | // 设置Facade的IOC容器 177 | Facade::setFacadeApplication($app); 178 | // 注册aliases 179 | AliasLoader::getInstance(array_merge( 180 | $app->make('config')->get('app.aliases', []), 181 | $app->make(PackageManifest::class)->aliases() 182 | ))->register(); 183 | } 184 | } 185 | // vendor/laravel/framework/src/Illuminate/Foundation/AliasLoader.php 186 | class AliasLoader 187 | { 188 | public function register() 189 | { 190 | if (! $this->registered) { 191 | $this->prependToLoaderStack(); 192 | 193 | $this->registered = true; 194 | } 195 | } 196 | 197 | protected function prependToLoaderStack() 198 | { 199 | // 在自动加载中这个函数用于解析命名空间,在这里用于解析别名的真正类名。 200 | spl_autoload_register([$this, 'load'], true, true); 201 | } 202 | 203 | public function load($alias) 204 | { 205 | if (static::$facadeNamespace && strpos($alias, static::$facadeNamespace) === 0) { 206 | $this->loadFacade($alias); 207 | 208 | return true; 209 | } 210 | 211 | // 最终的落实处 212 | if (isset($this->aliases[$alias])) { 213 | return class_alias($this->aliases[$alias], $alias); 214 | } 215 | } 216 | 217 | } 218 | ``` -------------------------------------------------------------------------------- /php/laravel/服务容器.md: -------------------------------------------------------------------------------- 1 | # 服务容器 2 | 3 | 4 | 5 | - [服务容器](#服务容器) 6 | - [一、问题](#一问题) 7 | - [二、原理](#二原理) 8 | 9 | 10 | 11 | 前言:`类`、`接口`、`对象`,接口是一组规范,类是接口的实现,对象是类的实例 12 | 13 | ## 一、问题 14 | 15 | 下面的例子中`SuperModuleInterface $module`注入到`class Superman`类中,实现`依赖注入(DI)`,又因为`SuperModuleInterface`是一个接口,也可以叫模组,因此实现了`控制反转(IOC)`,控制权限移到了接口 16 | 17 | ```php 18 | interface SuperModuleInterface 19 | { 20 | /** 21 | * 超能力激活方法 22 | * 23 | * 任何一个超能力都得有该方法,并拥有一个参数 24 | *@param array $target 针对目标,可以是一个或多个,自己或他人 25 | */ 26 | public function activate(array $target); 27 | } 28 | 29 | /** 30 | * X-超能量 31 | */ 32 | class XPower implements SuperModuleInterface 33 | { 34 | public function activate(array $target) 35 | { 36 | // 37 | } 38 | } 39 | 40 | /** 41 | * 终极炸弹 (就这么俗) 42 | */ 43 | class UltraBomb implements SuperModuleInterface 44 | { 45 | public function activate(array $target) 46 | { 47 | // 48 | } 49 | } 50 | 51 | class Superman 52 | { 53 | protected $module; 54 | 55 | public function __construct(SuperModuleInterface $module) 56 | { 57 | $this->module = $module 58 | } 59 | } 60 | 61 | // 超能力模组 62 | $superModule = new XPower; 63 | 64 | // 初始化一个超人,并注入一个超能力模组依赖 65 | $superMan = new Superman($superModule); 66 | ``` 67 | 68 | ## 二、原理 69 | 70 | ```php 71 | // vendor/laravel/framework/src/Illuminate/Container/Container.php 72 | class Container implements ArrayAccess, ContainerContract 73 | { 74 | // 绑定实例到容器 75 | public function bind($abstract, $concrete = null, $shared = false) 76 | { 77 | $this->dropStaleInstances($abstract); 78 | 79 | if (is_null($concrete)) { 80 | $concrete = $abstract; 81 | } 82 | 83 | if (! $concrete instanceof Closure) { 84 | $concrete = $this->getClosure($abstract, $concrete); 85 | } 86 | 87 | $this->bindings[$abstract] = compact('concrete', 'shared'); 88 | 89 | if ($this->resolved($abstract)) { 90 | $this->rebound($abstract); 91 | } 92 | } 93 | 94 | public function make($abstract, array $parameters = []) 95 | { 96 | return $this->resolve($abstract, $parameters); 97 | } 98 | 99 | // 从容器中解析出实例 100 | protected function resolve($abstract, $parameters = []) 101 | { 102 | $abstract = $this->getAlias($abstract); 103 | 104 | $needsContextualBuild = ! empty($parameters) || ! is_null( 105 | $this->getContextualConcrete($abstract) 106 | ); 107 | 108 | if (isset($this->instances[$abstract]) && ! $needsContextualBuild) { 109 | return $this->instances[$abstract]; 110 | } 111 | 112 | $this->with[] = $parameters; 113 | 114 | $concrete = $this->getConcrete($abstract); 115 | 116 | if ($this->isBuildable($concrete, $abstract)) { 117 | $object = $this->build($concrete); 118 | } else { 119 | $object = $this->make($concrete); 120 | } 121 | 122 | foreach ($this->getExtenders($abstract) as $extender) { 123 | $object = $extender($object, $this); 124 | } 125 | 126 | if ($this->isShared($abstract) && ! $needsContextualBuild) { 127 | $this->instances[$abstract] = $object; 128 | } 129 | 130 | $this->fireResolvingCallbacks($abstract, $object); 131 | 132 | $this->resolved[$abstract] = true; 133 | 134 | array_pop($this->with); 135 | 136 | return $object; 137 | } 138 | 139 | // 构建对象 140 | public function build($concrete) 141 | { 142 | if ($concrete instanceof Closure) { 143 | return $concrete($this, $this->getLastParameterOverride()); 144 | } 145 | 146 | // 通过反射取得实例 147 | $reflector = new ReflectionClass($concrete); 148 | 149 | if (! $reflector->isInstantiable()) { 150 | return $this->notInstantiable($concrete); 151 | } 152 | 153 | $this->buildStack[] = $concrete; 154 | 155 | $constructor = $reflector->getConstructor(); 156 | 157 | if (is_null($constructor)) { 158 | array_pop($this->buildStack); 159 | 160 | return new $concrete; 161 | } 162 | 163 | $dependencies = $constructor->getParameters(); 164 | 165 | $instances = $this->resolveDependencies( 166 | $dependencies 167 | ); 168 | 169 | array_pop($this->buildStack); 170 | 171 | // 返回实例 172 | return $reflector->newInstanceArgs($instances); 173 | } 174 | 175 | } 176 | ``` 177 | -------------------------------------------------------------------------------- /php/modern/.gitignore: -------------------------------------------------------------------------------- 1 | vendor 2 | src/config.php -------------------------------------------------------------------------------- /php/modern/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "require": { 3 | "monolog/monolog": "1.*", 4 | "league/csv": "9.1.*", 5 | "filp/whoops": "^2.2" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /php/modern/logs/dev.log: -------------------------------------------------------------------------------- 1 | [2018-07-29 16:28:48] app.DEBUG: 这是个bug [] [] 2 | [2018-07-29 16:28:48] app.WARNING: 这是个警告 [] [] 3 | -------------------------------------------------------------------------------- /php/modern/logs/pro.log: -------------------------------------------------------------------------------- 1 | [2018-07-29 16:28:48] app.WARNING: 这是个警告 [] [] 2 | -------------------------------------------------------------------------------- /php/modern/src/closure.php: -------------------------------------------------------------------------------- 1 | 1) 20 | return $num + $n; 21 | else 22 | return $num; 23 | }, [1, 2, 3]); 24 | 25 | print_r($number); -------------------------------------------------------------------------------- /php/modern/src/config.php: -------------------------------------------------------------------------------- 1 | '149.28.205.238', 11 | 'port' => 3306, 12 | 'db_name' => 'pdo', 13 | 'username' => 'root', 14 | 'password' => 'xxx', 15 | 'charset' => 'utf8', 16 | ]; 17 | -------------------------------------------------------------------------------- /php/modern/src/exception.php: -------------------------------------------------------------------------------- 1 | pushHandler(new PrettyPageHandler()); 21 | $whoops->register(); 22 | 23 | $e = new \Exception('omgzui', 400); 24 | 25 | $code = $e->getCode(); 26 | $message = $e->getMessage(); 27 | 28 | var_dump($code); 29 | var_dump($message); 30 | 31 | 32 | var_dump(1 / 0); -------------------------------------------------------------------------------- /php/modern/src/filter.php: -------------------------------------------------------------------------------- 1 | 12]); 23 | // 验证hash 24 | password_verify($password, $password_hash); 25 | // 刷新hash 26 | password_needs_rehash($password_hash, PASSWORD_DEFAULT, ['cost' => 15]); 27 | */ 28 | -------------------------------------------------------------------------------- /php/modern/src/log.php: -------------------------------------------------------------------------------- 1 | pushHandler(new StreamHandler('../logs/dev.log', Logger::DEBUG)); 18 | $log->pushHandler(new StreamHandler('../logs/pro.log', Logger::WARNING)); 19 | 20 | $log->debug('这是个bug'); 21 | $log->warning('这是个警告'); 22 | -------------------------------------------------------------------------------- /php/modern/src/pdo.php: -------------------------------------------------------------------------------- 1 | query('select version()'); 30 | // var_dump($row = $db->fetch()[0]); 31 | 32 | // 预处理 33 | $s = "select * from user where name = :name"; 34 | $db = $pdo->prepare($s); 35 | $name = 'omgzui'; 36 | $db->bindValue(':name', $name, PDO::PARAM_STR); 37 | $db->execute(); 38 | // PDO::FETCH_ASSOC 关联数组 39 | // PDO::FETCH_OBJ 关联对象 40 | while (($row = $db->fetch(PDO::FETCH_ASSOC))) { 41 | echo $row['id'] . ' => ' . $row['name'] . PHP_EOL; 42 | } 43 | 44 | // // 事务 45 | // $pdo->beginTransaction(); 46 | // // balabala 47 | // $pdo->commit(); 48 | } catch (\PDOException $e) { 49 | echo $e->getMessage(); 50 | exit(); 51 | } -------------------------------------------------------------------------------- /php/modern/src/scan.php: -------------------------------------------------------------------------------- 1 | get($item[0]); 23 | 24 | if ($httpRes->getStatusCode() >= 400) { 25 | throw new \Exception(); 26 | } 27 | } catch (\Exception $e) { 28 | echo $item[0] . PHP_EOL; 29 | } 30 | } -------------------------------------------------------------------------------- /php/modern/src/urls.csv: -------------------------------------------------------------------------------- 1 | https://apple.com 2 | http://sdsdg.org 3 | http://php.net -------------------------------------------------------------------------------- /public/img/explain.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OMGZui/noteBook/19d48d912e5e07271b370dbe00e498e5f18a29e7/public/img/explain.jpg -------------------------------------------------------------------------------- /public/img/html+css/box.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OMGZui/noteBook/19d48d912e5e07271b370dbe00e498e5f18a29e7/public/img/html+css/box.jpg -------------------------------------------------------------------------------- /public/img/html+css/dom.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OMGZui/noteBook/19d48d912e5e07271b370dbe00e498e5f18a29e7/public/img/html+css/dom.jpg -------------------------------------------------------------------------------- /public/img/html+css/rule.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OMGZui/noteBook/19d48d912e5e07271b370dbe00e498e5f18a29e7/public/img/html+css/rule.jpg -------------------------------------------------------------------------------- /public/img/http/attack.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OMGZui/noteBook/19d48d912e5e07271b370dbe00e498e5f18a29e7/public/img/http/attack.jpg -------------------------------------------------------------------------------- /public/img/http/client1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OMGZui/noteBook/19d48d912e5e07271b370dbe00e498e5f18a29e7/public/img/http/client1.jpg -------------------------------------------------------------------------------- /public/img/http/client2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OMGZui/noteBook/19d48d912e5e07271b370dbe00e498e5f18a29e7/public/img/http/client2.jpg -------------------------------------------------------------------------------- /public/img/http/http_trans.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OMGZui/noteBook/19d48d912e5e07271b370dbe00e498e5f18a29e7/public/img/http/http_trans.jpg -------------------------------------------------------------------------------- /public/img/http/http_trans2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OMGZui/noteBook/19d48d912e5e07271b370dbe00e498e5f18a29e7/public/img/http/http_trans2.jpg -------------------------------------------------------------------------------- /public/img/http/request.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OMGZui/noteBook/19d48d912e5e07271b370dbe00e498e5f18a29e7/public/img/http/request.jpg -------------------------------------------------------------------------------- /public/img/http/response.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OMGZui/noteBook/19d48d912e5e07271b370dbe00e498e5f18a29e7/public/img/http/response.jpg -------------------------------------------------------------------------------- /public/img/http/three_way_handshanking.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OMGZui/noteBook/19d48d912e5e07271b370dbe00e498e5f18a29e7/public/img/http/three_way_handshanking.jpg -------------------------------------------------------------------------------- /public/img/http/uri.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OMGZui/noteBook/19d48d912e5e07271b370dbe00e498e5f18a29e7/public/img/http/uri.jpg -------------------------------------------------------------------------------- /public/img/mysql_transaction.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OMGZui/noteBook/19d48d912e5e07271b370dbe00e498e5f18a29e7/public/img/mysql_transaction.jpg -------------------------------------------------------------------------------- /public/img/nf/1nf.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OMGZui/noteBook/19d48d912e5e07271b370dbe00e498e5f18a29e7/public/img/nf/1nf.jpg -------------------------------------------------------------------------------- /public/img/nf/1nfS.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OMGZui/noteBook/19d48d912e5e07271b370dbe00e498e5f18a29e7/public/img/nf/1nfS.jpg -------------------------------------------------------------------------------- /public/img/nf/2nf_e.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OMGZui/noteBook/19d48d912e5e07271b370dbe00e498e5f18a29e7/public/img/nf/2nf_e.jpg -------------------------------------------------------------------------------- /public/img/nf/2nf_p.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OMGZui/noteBook/19d48d912e5e07271b370dbe00e498e5f18a29e7/public/img/nf/2nf_p.jpg -------------------------------------------------------------------------------- /public/img/nf/2nf_p_e.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OMGZui/noteBook/19d48d912e5e07271b370dbe00e498e5f18a29e7/public/img/nf/2nf_p_e.jpg -------------------------------------------------------------------------------- /public/img/nf/3nf_e.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OMGZui/noteBook/19d48d912e5e07271b370dbe00e498e5f18a29e7/public/img/nf/3nf_e.jpg -------------------------------------------------------------------------------- /public/img/nf/3nf_s.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OMGZui/noteBook/19d48d912e5e07271b370dbe00e498e5f18a29e7/public/img/nf/3nf_s.jpg -------------------------------------------------------------------------------- /public/img/october/文章组件.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OMGZui/noteBook/19d48d912e5e07271b370dbe00e498e5f18a29e7/public/img/october/文章组件.jpg -------------------------------------------------------------------------------- /public/img/october/文章组件属性.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OMGZui/noteBook/19d48d912e5e07271b370dbe00e498e5f18a29e7/public/img/october/文章组件属性.jpg -------------------------------------------------------------------------------- /public/img/process.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OMGZui/noteBook/19d48d912e5e07271b370dbe00e498e5f18a29e7/public/img/process.jpg -------------------------------------------------------------------------------- /public/img/tcp-ip/arp.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OMGZui/noteBook/19d48d912e5e07271b370dbe00e498e5f18a29e7/public/img/tcp-ip/arp.jpg -------------------------------------------------------------------------------- /public/img/tcp-ip/cast.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OMGZui/noteBook/19d48d912e5e07271b370dbe00e498e5f18a29e7/public/img/tcp-ip/cast.jpg -------------------------------------------------------------------------------- /public/img/tcp-ip/data-head.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OMGZui/noteBook/19d48d912e5e07271b370dbe00e498e5f18a29e7/public/img/tcp-ip/data-head.jpg -------------------------------------------------------------------------------- /public/img/tcp-ip/dhcp.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OMGZui/noteBook/19d48d912e5e07271b370dbe00e498e5f18a29e7/public/img/tcp-ip/dhcp.jpg -------------------------------------------------------------------------------- /public/img/tcp-ip/diff.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OMGZui/noteBook/19d48d912e5e07271b370dbe00e498e5f18a29e7/public/img/tcp-ip/diff.jpg -------------------------------------------------------------------------------- /public/img/tcp-ip/dns.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OMGZui/noteBook/19d48d912e5e07271b370dbe00e498e5f18a29e7/public/img/tcp-ip/dns.jpg -------------------------------------------------------------------------------- /public/img/tcp-ip/exchange.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OMGZui/noteBook/19d48d912e5e07271b370dbe00e498e5f18a29e7/public/img/tcp-ip/exchange.jpg -------------------------------------------------------------------------------- /public/img/tcp-ip/frame.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OMGZui/noteBook/19d48d912e5e07271b370dbe00e498e5f18a29e7/public/img/tcp-ip/frame.jpg -------------------------------------------------------------------------------- /public/img/tcp-ip/ip.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OMGZui/noteBook/19d48d912e5e07271b370dbe00e498e5f18a29e7/public/img/tcp-ip/ip.jpg -------------------------------------------------------------------------------- /public/img/tcp-ip/ipv6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OMGZui/noteBook/19d48d912e5e07271b370dbe00e498e5f18a29e7/public/img/tcp-ip/ipv6.jpg -------------------------------------------------------------------------------- /public/img/tcp-ip/layer.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OMGZui/noteBook/19d48d912e5e07271b370dbe00e498e5f18a29e7/public/img/tcp-ip/layer.jpg -------------------------------------------------------------------------------- /public/img/tcp-ip/link.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OMGZui/noteBook/19d48d912e5e07271b370dbe00e498e5f18a29e7/public/img/tcp-ip/link.jpg -------------------------------------------------------------------------------- /public/img/tcp-ip/network.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OMGZui/noteBook/19d48d912e5e07271b370dbe00e498e5f18a29e7/public/img/tcp-ip/network.jpg -------------------------------------------------------------------------------- /public/img/tcp-ip/open.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OMGZui/noteBook/19d48d912e5e07271b370dbe00e498e5f18a29e7/public/img/tcp-ip/open.jpg -------------------------------------------------------------------------------- /public/img/tcp-ip/osi.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OMGZui/noteBook/19d48d912e5e07271b370dbe00e498e5f18a29e7/public/img/tcp-ip/osi.jpg -------------------------------------------------------------------------------- /public/img/tcp-ip/packet.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OMGZui/noteBook/19d48d912e5e07271b370dbe00e498e5f18a29e7/public/img/tcp-ip/packet.jpg -------------------------------------------------------------------------------- /public/img/tcp-ip/port.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OMGZui/noteBook/19d48d912e5e07271b370dbe00e498e5f18a29e7/public/img/tcp-ip/port.jpg -------------------------------------------------------------------------------- /public/img/tcp-ip/protocol.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OMGZui/noteBook/19d48d912e5e07271b370dbe00e498e5f18a29e7/public/img/tcp-ip/protocol.jpg -------------------------------------------------------------------------------- /public/img/tcp-ip/rarp.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OMGZui/noteBook/19d48d912e5e07271b370dbe00e498e5f18a29e7/public/img/tcp-ip/rarp.jpg -------------------------------------------------------------------------------- /public/img/tcp-ip/ssh.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OMGZui/noteBook/19d48d912e5e07271b370dbe00e498e5f18a29e7/public/img/tcp-ip/ssh.jpg -------------------------------------------------------------------------------- /public/img/tcp-ip/syn.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OMGZui/noteBook/19d48d912e5e07271b370dbe00e498e5f18a29e7/public/img/tcp-ip/syn.jpg -------------------------------------------------------------------------------- /public/img/tcp-ip/t66y.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OMGZui/noteBook/19d48d912e5e07271b370dbe00e498e5f18a29e7/public/img/tcp-ip/t66y.jpg -------------------------------------------------------------------------------- /public/img/tcp-ip/tcp.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OMGZui/noteBook/19d48d912e5e07271b370dbe00e498e5f18a29e7/public/img/tcp-ip/tcp.jpg -------------------------------------------------------------------------------- /public/img/tcp-ip/telnet.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OMGZui/noteBook/19d48d912e5e07271b370dbe00e498e5f18a29e7/public/img/tcp-ip/telnet.jpg -------------------------------------------------------------------------------- /public/img/tcp-ip/udp.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OMGZui/noteBook/19d48d912e5e07271b370dbe00e498e5f18a29e7/public/img/tcp-ip/udp.jpg -------------------------------------------------------------------------------- /public/img/tcp-ip/use.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OMGZui/noteBook/19d48d912e5e07271b370dbe00e498e5f18a29e7/public/img/tcp-ip/use.jpg -------------------------------------------------------------------------------- /public/img/tcp-ip/wifi.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OMGZui/noteBook/19d48d912e5e07271b370dbe00e498e5f18a29e7/public/img/tcp-ip/wifi.jpg -------------------------------------------------------------------------------- /public/readme.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OMGZui/noteBook/19d48d912e5e07271b370dbe00e498e5f18a29e7/public/readme.md -------------------------------------------------------------------------------- /springboot.md: -------------------------------------------------------------------------------- 1 | # springboot 2 | 3 | ## 简介 4 | 5 | ## 安装 6 | 7 | ## 配置 8 | 9 | ## web 10 | 11 | ## 工具 12 | 13 | ### rocketMQ 14 | 15 | -------------------------------------------------------------------------------- /supervisor.md: -------------------------------------------------------------------------------- 1 | # supervisor 2 | 3 | 4 | 5 | - [supervisor](#supervisor) 6 | - [零、supervisor是什么](#零supervisor是什么) 7 | - [一、安装](#一安装) 8 | - [二、配置](#二配置) 9 | - [三、管理服务](#三管理服务) 10 | - [1、管理php-fpm](#1管理php-fpm) 11 | - [2、管理nginx](#2管理nginx) 12 | - [四、supervisorctl](#四supervisorctl) 13 | - [五、参考资料](#五参考资料) 14 | 15 | 16 | 17 | ## 零、supervisor是什么 18 | 19 | Supervisor是用Python开发的一套通用的进程管理程序,能将一个普通的命令行进程变为后台daemon,并监控进程状态,异常退出时能自动重启。它是通过fork/exec的方式把这些被管理的进程当作supervisor的子进程来启动,这样只要在supervisor的配置文件中,把要管理的进程的可执行文件的路径写进去即可。也实现当子进程挂掉的时候,父进程可以准确获取子进程挂掉的信息的,可以选择是否自己启动和报警。 20 | 21 | ## 一、安装 22 | 23 | ```bash 24 | apt -y install supervisor 25 | yum -y install supervisor 26 | ``` 27 | 28 | ## 二、配置 29 | 30 | ```bash 31 | [unix_http_server] 32 | file=/var/run/supervisor.sock 33 | chmod=0700 34 | 35 | [inet_http_server] 36 | port=0.0.0.0:7020 37 | username=root 38 | password=xxxxxx 39 | 40 | [supervisord] 41 | logfile=/var/log/supervisor/supervisord.log 42 | pidfile=/var/run/supervisord.pid 43 | childlogdir=/var/log/supervisor 44 | 45 | [rpcinterface:supervisor] 46 | supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface 47 | 48 | [supervisorctl] 49 | serverurl=unix:///var/run/supervisor.sock 50 | 51 | [include] 52 | files = /etc/supervisor/conf.d/*.conf 53 | 54 | ``` 55 | 56 | ## 三、管理服务 57 | 58 | - 需要前台运行交于supervisor控制,原理是fork一个守护进程进行监控 59 | - program 标识,比如php-fpm,可以在后台supervisorctl中进行start/stop/restart操作 60 | - command 命令,需要加上sleep 1,防止进程还没退出supervisor就去检测,还挺好用 61 | 62 | ### 1、管理php-fpm 63 | 64 | ```bash 65 | [program:php-fpm] 66 | command=bash -c "sleep 1 && sudo /usr/local/php7.4/sbin/php-fpm" 67 | process_name=%(program_name)s 68 | autostart=true 69 | autorestart=true 70 | startretries=5 71 | exitcodes=0,2,70 72 | stopsignal=QUIT 73 | stopwaitsecs=2 74 | stdout_logfile=/var/log/supervisor/php-fpm.log 75 | ``` 76 | 77 | ```bash 78 | ps -ef|grep php-fpm 79 | root 23034 22175 0 23:37 ? 00:00:00 sudo /usr/local/php7.4/sbin/php-fpm 80 | root 23043 23034 0 23:37 ? 00:00:00 php-fpm: master process (/usr/local/php7.4/etc/php-fpm.conf) 81 | www-data 23044 23043 0 23:37 ? 00:00:00 php-fpm: pool www 82 | www-data 23045 23043 0 23:37 ? 00:00:00 php-fpm: pool www 83 | ``` 84 | 85 | ### 2、管理nginx 86 | 87 | ```bash 88 | [program:nginx] 89 | command=bash -c "sleep 1 && sudo /usr/local/nginx/sbin/nginx -g 'daemon off;'" 90 | process_name=%(program_name)s 91 | autostart=true 92 | autorestart=true 93 | startretries=5 94 | exitcodes=0,2,70 95 | stopsignal=INT 96 | stopwaitsecs=2 97 | stdout_logfile=/var/log/supervisor/nginx.log 98 | ``` 99 | 100 | ```bash 101 | ps -ef|grep nginx 102 | root 22613 22175 0 23:35 ? 00:00:00 sudo /usr/local/nginx/sbin/nginx -g daemon off; 103 | root 22616 22613 0 23:35 ? 00:00:00 nginx: master process /usr/local/nginx/sbin/nginx -g daemon off; 104 | www-data 22617 22616 0 23:35 ? 00:00:00 nginx: worker process 105 | www-data 22618 22616 0 23:35 ? 00:00:00 nginx: worker process 106 | www-data 22619 22616 0 23:35 ? 00:00:00 nginx: worker process 107 | www-data 22620 22616 0 23:35 ? 00:00:00 nginx: worker process 108 | ``` 109 | 110 | ## 四、supervisorctl 111 | 112 | `supervisorctl` 113 | 114 | ```bash 115 | supervisor> status 116 | nginx RUNNING pid 22613, uptime 0:03:40 117 | php-fpm RUNNING pid 23034, uptime 0:01:43 118 | supervisor> ? 119 | 120 | default commands (type help ): 121 | ===================================== 122 | add exit open reload restart start tail 123 | avail fg pid remove shutdown status update 124 | clear maintail quit reread signal stop version 125 | 126 | ``` 127 | 128 | ## 五、参考资料 129 | 130 | [Supervisor使用详解](https://www.jianshu.com/p/0b9054b33db3) -------------------------------------------------------------------------------- /tests/LinkListTest.php: -------------------------------------------------------------------------------- 1 | expectOutputString('1 2 3 4 5 10 9 8 7 6 '); 19 | 20 | $link = new LinkList([1, 2, 3, 4, 5, 10, 9, 8, 7, 6]); 21 | $head = $link->head; 22 | $link->show($head); 23 | } 24 | 25 | public function testInsert() 26 | { 27 | $this->expectOutputString('100 1 2 3 4 5 10 9 8 7 6 '); 28 | 29 | $link = new LinkList([1, 2, 3, 4, 5, 10, 9, 8, 7, 6]); 30 | $head = $link->head; 31 | if ($link->insert($head, 1, 100)) { 32 | $link->show($head); 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /tests/PredefinedInterfaces/ArrayAccessTest.php: -------------------------------------------------------------------------------- 1 | add(['one' => 1]); 20 | $obj->add(['two' => 2]); 21 | $obj->add(['three' => 3]); 22 | 23 | $this->assertTrue(isset($obj['two'])); 24 | $this->assertEquals(2, $obj['two']); 25 | 26 | $obj['four'] = 4; 27 | $this->assertTrue(isset($obj['four'])); 28 | $this->assertEquals(4, $obj['four']); 29 | 30 | unset($obj['four']); 31 | $this->assertFalse(isset($obj['four'])); 32 | 33 | } 34 | } -------------------------------------------------------------------------------- /tests/PredefinedInterfaces/ClosureTest.php: -------------------------------------------------------------------------------- 1 | assertEquals(2, $obj->add(function (array $params) { 21 | return ++$params[0]; 22 | }, [1])); 23 | 24 | // 测试同一个实例 25 | $newObj = $obj->test(function (array $params){ 26 | return $this; 27 | }, [1]); 28 | $this->assertTrue($newObj instanceof $obj); 29 | } 30 | 31 | public function testClosureBind() 32 | { 33 | $obj = new ClosureBind(); 34 | $obj->addMethod('add', function (array $params) { 35 | return ++$params[0]; 36 | }); 37 | $this->assertEquals(2, $obj->add([1])); 38 | 39 | // 测试同一个实例 40 | $obj->addMethod('test', function (array $params) { 41 | return $this; 42 | }); 43 | $this->assertTrue($obj->test([1]) instanceof $obj); 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /tests/PredefinedInterfaces/IteratorAggregateTest.php: -------------------------------------------------------------------------------- 1 | $value) { 25 | $testKey[] = $key; 26 | $testValue[] = $value; 27 | } 28 | 29 | $this->assertInstanceOf(\Traversable::class, $aggregate); 30 | 31 | $this->assertSame( 32 | ['property1', 'property2', 'property3', 'property4'], 33 | $testKey 34 | ); 35 | 36 | $this->assertSame( 37 | ['one', 'two', 'three', 'four'], 38 | $testValue 39 | ); 40 | 41 | $testKey = []; 42 | $testValue = []; 43 | 44 | // 可见直接迭代类本身和迭代getIterator()是一样的 45 | foreach ($aggregate->getIterator() as $key => $value) { 46 | $testKey[] = $key; 47 | $testValue[] = $value; 48 | } 49 | 50 | $this->assertInstanceOf(\Traversable::class, $aggregate); 51 | 52 | $this->assertSame( 53 | ['property1', 'property2', 'property3', 'property4'], 54 | $testKey 55 | ); 56 | 57 | $this->assertSame( 58 | ['one', 'two', 'three', 'four'], 59 | $testValue 60 | ); 61 | } 62 | } -------------------------------------------------------------------------------- /tests/PredefinedInterfaces/IteratorTest.php: -------------------------------------------------------------------------------- 1 | valid()->key()->current()->next()->valid()->key()->current()->next() 20 | $iterator = new MyIterator(); 21 | $this->assertInstanceOf(\Traversable::class, $iterator); 22 | 23 | $iterator->add(1); 24 | $iterator->add(2); 25 | $iterator->add(3); 26 | 27 | $exceptArr = []; 28 | foreach ($iterator as $item) { 29 | $exceptArr[] = $item; 30 | } 31 | 32 | $this->assertSame( 33 | [1, 2, 3], 34 | $exceptArr 35 | ); 36 | 37 | $exceptArr2 = []; 38 | $iterator->rewind(); 39 | while ($iterator->valid()) { 40 | $exceptArr2[] = $iterator->current(); 41 | $iterator->next(); 42 | } 43 | 44 | $this->assertSame( 45 | [1, 2, 3], 46 | $exceptArr2 47 | ); 48 | 49 | } 50 | } -------------------------------------------------------------------------------- /tests/PredefinedInterfaces/SerializableTest.php: -------------------------------------------------------------------------------- 1 | add('你个小可爱'); 22 | 23 | $ser = serialize($obj); 24 | $serUn = unserialize($ser); 25 | $this->assertEquals('你个小可爱', $serUn->getData()); 26 | 27 | } 28 | } -------------------------------------------------------------------------------- /tests/PredefinedInterfaces/TraversableTest.php: -------------------------------------------------------------------------------- 1 | assertInstanceOf(\Traversable::class, new MyTraversable()); 20 | } 21 | } -------------------------------------------------------------------------------- /tests/SortTest.php: -------------------------------------------------------------------------------- 1 | except = range(1, 5); 26 | } 27 | 28 | protected function tearDown() 29 | { 30 | parent::tearDown(); 31 | unset($this->except); 32 | } 33 | 34 | public function testBubble() 35 | { 36 | $arr = $this->except; 37 | shuffle($arr); 38 | $sort = SortFactory::getInstance(new BubbleSort()); 39 | $this->assertSame($this->except, $sort->sort($arr)); 40 | } 41 | 42 | public function testQuick() 43 | { 44 | $arr = $this->except; 45 | shuffle($arr); 46 | $sort = SortFactory::getInstance(new QuickSort()); 47 | $this->assertSame($this->except, $sort->sort($arr)); 48 | } 49 | 50 | public function testInsert() 51 | { 52 | $arr = $this->except; 53 | shuffle($arr); 54 | $sort = SortFactory::getInstance(new InsertSort()); 55 | $this->assertSame($this->except, $sort->sort($arr)); 56 | } 57 | 58 | public function testSelect() 59 | { 60 | $arr = $this->except; 61 | shuffle($arr); 62 | $sort = SortFactory::getInstance(new SelectSort()); 63 | $this->assertSame($this->except, $sort->sort($arr)); 64 | } 65 | } -------------------------------------------------------------------------------- /数据库范式.md: -------------------------------------------------------------------------------- 1 | # 数据库范式 2 | 3 | 4 | 5 | - [数据库范式](#数据库范式) 6 | - [零、问题](#零问题) 7 | - [一、第一范式](#一第一范式) 8 | - [二、第二范式](#二第二范式) 9 | - [三、第三范式](#三第三范式) 10 | - [四、结束语](#四结束语) 11 | - [五、参考资料](#五参考资料) 12 | 13 | 14 | 15 | 前言:`p`项目,`e`员工,`s`薪水 16 | 17 | ## 零、问题 18 | 19 | 数据应该尽可能少地冗余,这意味着重复数据应该减少到最少。比如说,一个部门雇员的电话不应该被存储在不同的表中, 因为这里的电话号码是雇员的一个属性。如果存在过多的冗余数据,这就意味着要占用了更多的物理空间,同时也对数据的维护和一致性检查带来了问题,当这个员工的电话号码变化时,冗余数据会导致对多个表的更新动作,如果有一个表不幸被忽略了,那么就可能导致数据的不一致性。 20 | 21 | **表 1-1** 22 | 23 | ![1nf](https://raw.githubusercontent.com/OMGZui/noteBook/master/public/img/nf/1nf.jpg) 24 | 25 | 我们可以看到,这张表一共有六个字段,分析每个字段都有重复的值出现,也就是说,存在数据冗余问题。这将潜在地造成数据操作(比如删除、更新等操作)时的异常情况,因此,需要进行规范化。 26 | 27 | ## 一、第一范式 28 | 29 | 参照范式的定义,考察上表,我们发现,这张表已经满足了第一范式的要求。 30 | 31 | 1、因为这张表中字段都是单一属性的,不可再分 32 | 33 | 2、而且每一行的记录都是没有重复的 34 | 35 | 3、存在主属性,而且所有的属性都是依赖于主属性 36 | 37 | 4、所有的主属性都已经定义 38 | 39 | 可以看到,属性对``是主键,其他所有的属性都依赖于该主键。 40 | 41 | ## 二、第二范式 42 | 43 | 根据第二范式的定义,转化为二范式就是消除部分依赖。 44 | 45 | 1、数据冗余:每一个字段都有值重复 46 | 47 | 2、更新异常:比如对`p_name`值"TPMS"做了修改,那么就要一次更新该字段的多个值 48 | 49 | 3、插入异常:如果新建了一个`p`,名字为"TPT", 但是还没有`e`加入,那么`e_id`将会空缺,而该字段是主键的一部分,因此将无法插入记录 50 | 51 | 4、删除异常:如果一个员工 200003, Kevin 离职了,要将该员工的记录从表中删除,而此时相关的`s_category` C 也将丢失, 因为再没有别的行纪录下 ``s_category`C的信息 52 | 53 | 因此,我们需要将存在部分依赖关系的主属性和非主属性从满足第一范式的表中分离出来,形成一张新的表,而新表和旧表之间是一对多的关系。由此,我们得到: 54 | 55 | **表 1-2** 56 | 57 | ![2nf_p](https://raw.githubusercontent.com/OMGZui/noteBook/master/public/img/nf/2nf_p.jpg) 58 | 59 | **表 1-3** 60 | 61 | ![2nf_e](https://raw.githubusercontent.com/OMGZui/noteBook/master/public/img/nf/2nf_e.jpg) 62 | 63 | **表 1-4** 64 | 65 | ![2nf_p_e](https://raw.githubusercontent.com/OMGZui/noteBook/master/public/img/nf/2nf_p_e.jpg) 66 | 67 | 这时候我们仔细观察一下表1-2, 1-3, 1-4, 我们发现插入异常已经不存在了,当我们引入一个新的`p`"TPT" 的时候,我们只需要向表1-2 中插入一条数据就可以了, 当有新人加入`p`"TPT" 的时候,我们需要向表1-3, 1-4 中各插入一条数据就可以了。虽然我们解决了一个大问题,但是仔细观察我们还是发现有问题存在。 68 | 69 | ## 三、第三范式 70 | 71 | 考察表前面生成的三张表,我们发现,表1-3存在传递依赖关系。而这是不满足三范式的规则的,存在以下的不足: 72 | 73 | 1、数据冗余:`s_category`和`s_package`的值有重复 74 | 75 | 2、更新异常:有重复的冗余信息,修改时需要同时修改多条记录,否则会出现数据不一致的情况 76 | 77 | 3、删除异常:同样的,如果员工 200003 Kevin 离开了公司,会直接导致 `s_category` C 的信息的丢失 78 | 79 | 因此,我们需要继续进行规范化的过程,把表1-3拆开,我们得到: 80 | 81 | **表 1-5** 82 | 83 | ![3nf_e](https://raw.githubusercontent.com/OMGZui/noteBook/master/public/img/nf/3nf_e.jpg) 84 | 85 | **表 1-6** 86 | 87 | ![3nf_s](https://raw.githubusercontent.com/OMGZui/noteBook/master/public/img/nf/3nf_s.jpg) 88 | 89 | 这时候如果 200003 Kevin 离开公司,我们只需要从表 1-5 中删除他就可以了, 存在于表1-6中的 `s_category` C 信息并不会丢失。但是我们要注意到除了表 1-5 中存在 Kevin 的信息之外, 表1-4中也存在 Kevin 的信息, 这很容易理解, 因为 Kevin 参与了项目 100001, TPMS, 所以当然也要从中删除。 90 | 91 | 至此,我们将表1-1经过规范化步骤,得到四张表,满足了三范式的约束要求,数据冗余、更新异常、插入异常和删除异常。 92 | 93 | 在三范式之上,还存在着更为严格约束的BC范式和四范式,但是这两种形式在商业应用中很少用到,在绝大多数情况下,三范式已经满足了数据库表规范化的要求,有效地解决了数据冗余和维护操作的异常问题。 94 | 95 | ## 四、结束语 96 | 97 | 在本文描述的过程中,我们通过结合实例的方法,通俗地演绎了数据表规范化的过程,并展示了在此过程中数据冗余、数据库操作异常等问题是如何得到解决的。 98 | 99 | 在具体的工程应用中,运用数据库规范化的方法来设计数据库表,将是具有现实意义的。 100 | 101 | ## 五、参考资料 102 | 103 | - [规范化-数据库设计原则](https://www.ibm.com/developerworks/cn/data/library/techarticles/dm-0605jiangt/index.html) -------------------------------------------------------------------------------- /未命名绘图.drawio: -------------------------------------------------------------------------------- 1 | ddG9DoMgEADgp2FXSH+cra1LJ4fORK5Cgh5BGm2fvhqkltgu5Pju4PghLG/Hi+VGXlGAJjQRI2EnQmmWJtM4w9PDLlugsUp4Sleo1AsWDGUPJaCPCh2idsrEWGPXQe0i49biEJfdUcddDW9gA1XN9VZvSjjp9UgPq5egGhk6p/vMZ1oeipeb9JILHL6IFYTlFtH5qB1z0PPbhXfx685/sp+DWejcjwVTsO49TaIPYsUb --------------------------------------------------------------------------------