summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorAdam Bard <github@adambard.com>2013-07-31 22:03:42 -0700
committerAdam Bard <github@adambard.com>2013-07-31 22:03:42 -0700
commit27c0560fdfe7bed63d544f6b58a919fa3e24b46f (patch)
treea367f97b1e0506a5e4eff68e1334f8e3057b8912
parentf6e87835cf5c1602f5f19c02eebccf325d7bd309 (diff)
parent1dd8abaa9d0bbf38e6b21181472d7a8ecdc6e484 (diff)
Merge pull request #147 from lichenbo/master-cn
Chinese translated version of c and elisp tutorial
-rwxr-xr-xzh-cn/c-cn.html.markdown394
-rwxr-xr-xzh-cn/elisp-cn.html.markdown340
-rwxr-xr-xzh-cn/java-cn.html.markdown404
-rwxr-xr-xzh-cn/php-cn.html.markdown635
4 files changed, 1773 insertions, 0 deletions
diff --git a/zh-cn/c-cn.html.markdown b/zh-cn/c-cn.html.markdown
new file mode 100755
index 00000000..ed55203c
--- /dev/null
+++ b/zh-cn/c-cn.html.markdown
@@ -0,0 +1,394 @@
+---
+language: c
+filename: learnc.c
+contributors:
+ - ["Adam Bard", "http://adambard.com/"]
+translators:
+ - ["Chenbo Li", "http://binarythink.net/"]
+---
+
+C语言在今天仍然是高性能计算的主要选择。
+
+C大概是大多数程序员用到的最接近底层的语言了,但是C语言本身不仅可以用来提升程序运行的速度
+注意看看C语言的文档,你就会知道C语言在内存管理方面的强大也是其他语言无法比拟的。
+
+```c
+// 用“//”来实现单行注释
+
+/*
+多行注释是这个样子的
+*/
+
+// 用#include来导入头文件
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+// 函数的标签(signature)应该放在.h文件中,并且引入到程序顶部
+// 也可以直接放到你的.c文件的最上面
+void function_1();
+void function_2();
+
+// c程序的入口是一个返回值为int型的函数,名字叫做main
+int main() {
+
+// 用printf来实现标准输出,这种输出也可以用格式来控制
+// %d 代表一个整数, \n 代表一个新行
+printf("%d\n", 0); // => 输出 0
+// 所有的语句都要以分号结束
+
+///////////////////////////////////////
+// 类型
+///////////////////////////////////////
+
+// 在使用变量之前我们必须先声明它们。
+// 变量在声明时需要指明其类型,而类型能够告诉系统这个变量所占用的空间
+
+// int型(整型)变量一般占用4个字节
+int x_int = 0;
+
+// short型(短整型)变量一般占用2个字节
+short x_short = 0;
+
+// char型(字符型)变量会占用1个字节
+char x_char = 0;
+char y_char = 'y'; // 字符变量的字面值需要用单引号包住
+
+// long型(长整型)一般需要4个字节到8个字节; 而long long型则至少需要8个字节(64位)
+
+long x_long = 0;
+long long x_long_long = 0;
+
+// float一般是用32位表示的浮点数字
+float x_float = 0.0;
+
+// double一般是用64位表示的浮点数字
+double x_double = 0.0;
+
+// 整数类型也可以有无符号的类型表示。这样这些变量就无法表示负数
+// 但是无符号整数所能表示的范围就可以比原来的整数大一些
+
+unsigned char ux_char;
+unsigned short ux_short;
+unsigned int ux_int;
+unsigned long long ux_long_long;
+
+// char类型一定会占用1个字节,但是其他的类型却会因具体机器的不同而各异
+// sizeof(T) 可以返回T类型在运行的机器上占用多少个字节
+// 这样你的代码就可以在各处正确运行了
+// 比如
+printf("%lu\n", sizeof(int)); // => 4 (字长为4的机器上)
+
+// 数组必须要在开始被初始化为特定的长度
+char my_char_array[20]; // 这个数组占据 1 * 20 = 20 个字节
+int my_int_array[20]; // 这个数组占据 4 * 20 = 80 个字节
+ // (这里我们假设字长为4)
+
+
+// 可以用下面的方法把数组初始化为0:
+char my_array[20] = {0};
+
+// 对数组任意存取就像其他语言的方式 -- 其实是其他的语言像C
+my_array[0]; // => 0
+
+// 数组是可变的,其实就是内存的映射!
+my_array[1] = 2;
+printf("%d\n", my_array[1]); // => 2
+
+// 字符串就是以 NUL (0x00) 这个字符结尾的字符数组,
+// 这个字符可以用'\0'来表示.
+// (在字符串字面值中我们不必输入这个字符,编译器会自动添加的)
+char a_string[20] = "This is a string";
+printf("%s\n", a_string); // %s 可以对字符串进行格式化
+
+/*
+也许你会注意到 a_string 实际上只有16个字节长.
+第17个字节是一个空字符(NUL)
+而第18, 19 和 20 个字符的值是不确定的。
+*/
+
+printf("%d\n", a_string[16]); // => 0
+
+///////////////////////////////////////
+// 操作符
+///////////////////////////////////////
+
+int i1 = 1, i2 = 2; // 多个变量声明的简写
+float f1 = 1.0, f2 = 2.0;
+
+// 算数运算
+i1 + i2; // => 3
+i2 - i1; // => 1
+i2 * i1; // => 2
+i1 / i2; // => 0 (0.5 会被化整为 0)
+
+f1 / f2; // => 0.5, 也许会有很小的误差
+
+// 取余运算
+11 % 3; // => 2
+
+// 比较操作符我们也很熟悉, 但是有一点,C中没有布尔类型
+// 而是用整形替代
+// 0 就是 false, 其他的就是 true. (比较操作符的返回值则仅有0和1)
+3 == 2; // => 0 (false)
+3 != 2; // => 1 (true)
+3 > 2; // => 1
+3 < 2; // => 0
+2 <= 2; // => 1
+2 >= 2; // => 1
+
+// 逻辑运算符需要作用于整数
+!3; // => 0 (非)
+!0; // => 1
+1 && 1; // => 1 (且)
+0 && 1; // => 0
+0 || 1; // => 1 (或)
+0 || 0; // => 0
+
+// 位运算
+~0x0F; // => 0xF0 (取反)
+0x0F & 0xF0; // => 0x00 (和)
+0x0F | 0xF0; // => 0xFF (或)
+0x04 ^ 0x0F; // => 0x0B (异或)
+0x01 << 1; // => 0x02 (左移1位)
+0x02 >> 1; // => 0x01 (右移1位)
+
+///////////////////////////////////////
+// 控制结构
+///////////////////////////////////////
+
+if (0) {
+ printf("I am never run\n");
+} else if (0) {
+ printf("I am also never run\n");
+} else {
+ printf("I print\n");
+}
+
+// While循环
+int ii = 0;
+while (ii < 10) {
+ printf("%d, ", ii++); // ii++ 在取值过后自增
+} // => 输出 "0, 1, 2, 3, 4, 5, 6, 7, 8, 9, "
+
+printf("\n");
+
+int kk = 0;
+do {
+ printf("%d, ", kk);
+} while (++kk < 10); // ++kk 先自增,在被取值
+// => 输出 "0, 1, 2, 3, 4, 5, 6, 7, 8, 9, "
+
+printf("\n");
+
+// For 循环
+int jj;
+for (jj=0; jj < 10; jj++) {
+ printf("%d, ", jj);
+} // => 输出 "0, 1, 2, 3, 4, 5, 6, 7, 8, 9, "
+
+printf("\n");
+
+///////////////////////////////////////
+// 类型转换
+///////////////////////////////////////
+
+// 在C中每个变量都有类型,你可以将变量的类型进行转换
+
+int x_hex = 0x01; // 可以用16进制赋值
+
+// 在类型转换时,数字本身的值会被保留下来
+printf("%d\n", x_hex); // => 输出 1
+printf("%d\n", (short) x_hex); // => 输出 1
+printf("%d\n", (char) x_hex); // => 输出 1
+
+// 类型转换时可能会造成溢出,而且不会抛出警告
+printf("%d\n", (char) 257); // => 1 (char的最大值为255)
+
+// 整数型和浮点型可以互相转换
+printf("%f\n", (float)100); // %f 表示单精度浮点
+printf("%lf\n", (double)100); // %lf 表示双精度浮点
+printf("%d\n", (char)100.0);
+
+///////////////////////////////////////
+// 指针
+///////////////////////////////////////
+
+// 指针变量是用来储存内存地址的变量
+// 指针变量的定义也会告诉你指向的地址的变量的类型
+// 你也可以得到某个变量的地址,并对它们进行操作
+
+int x = 0;
+printf("%p\n", &x); // 用 & 来获取变量的地址
+// (%p 表示一个指针)
+// => 输出某个内存地址
+
+// 指针类型在定义是需要以*结束
+int* px; // px是一个指向int型的指针
+px = &x; // 把x的地址保存到px中
+printf("%p\n", px); // => 输出内存中的某个地址
+
+// 要得到某个指针指向的内容的值,可以在指针前加一个*来取得(去引用)
+printf("%d\n", *px); // => 输出 0, 即x的值
+
+// 你也可以改变指针所指向的值
+// 此时你需要在*运算符后添加一个括号,因为++比*的优先级更高
+(*px)++; // 把px所指向的值增加2
+printf("%d\n", *px); // => 输出 1
+printf("%d\n", x); // => 输出 1
+
+int x_array[20]; // 数组是分配一系列连续空间的常用方式
+int xx;
+for (xx=0; xx<20; xx++) {
+ x_array[xx] = 20 - xx;
+} // 初始化 x_array 为 20, 19, 18,... 2, 1
+
+// 生命一个变量为指向整型的指针类型,并初始化为指向x_array
+int* x_ptr = x_array;
+// x_ptr现在指向了数组的第一个元素(即整数20).
+
+// 事实上数组本身就是指向它的第一个元素的指针
+printf("%d\n", *(x_ptr)); // => 输出 20
+printf("%d\n", x_array[0]); // => 输出 20
+
+// 指针的增减多少是依据它本身的类型而定的
+printf("%d\n", *(x_ptr + 1)); // => 输出 19
+printf("%d\n", x_array[1]); // => 输出 19
+
+// 你也可以通过标准库函数malloc来实现动态分配
+// 这个函数接受一个代表容量的参数
+// 系统会从堆区分配指定容量字节大小的空间
+int* my_ptr = (int*) malloc(sizeof(int) * 20);
+for (xx=0; xx<20; xx++) {
+ *(my_ptr + xx) = 20 - xx; // my_ptr[xx] = 20-xx 也可以
+} // 初始化内存为 20, 19, 18, 17... 2, 1 (as ints)
+
+// 如果对一些未分配的内存取值则会得到未知的结果
+printf("%d\n", *(my_ptr + 21)); // => 谁知道会输出什么
+
+// 当你通过malloc得到一块区域后,你需要释放它
+// 否则没人能够再次使用这块内存,直到程序结束为止
+free(my_ptr);
+
+// 字符串通常是字符数组,但是经常用字符指针表示
+// 指针:
+char* my_str = "This is my very own string";
+
+printf("%c\n", *my_str); // => 'T'
+
+function_1();
+} // main函数结束
+
+///////////////////////////////////////
+// 函数
+///////////////////////////////////////
+
+// 函数声明语法:
+// <返回值类型> <函数名称>(<参数>)
+
+int add_two_ints(int x1, int x2){
+ return x1 + x2; // 用return来返回一个值
+}
+
+/*
+函数是按值传递的, 但是你可以通过传递参数来传递引用,这样函数就可以更改值
+
+例子:字符串本身翻转
+*/
+
+// 类型为void的函数没有返回值
+void str_reverse(char* str_in){
+ char tmp;
+ int ii=0, len = strlen(str_in); // Strlen 是C标准库函数
+ for(ii=0; ii<len/2; ii++){
+ tmp = str_in[ii];
+ str_in[ii] = str_in[len - ii - 1]; // 从倒数第ii个开始
+ str_in[len - ii - 1] = tmp;
+ }
+}
+
+/*
+char c[] = "This is a test.";
+str_reverse(c);
+printf("%s\n", c); // => ".tset a si sihT"
+*/
+
+///////////////////////////////////////
+// 用户自定义类型和结构
+///////////////////////////////////////
+
+// Typedefs可以创建类型别名
+typedef int my_type;
+my_type my_type_var = 0;
+
+// 结构是一系列数据的集合
+struct rectangle {
+ int width;
+ int height;
+};
+
+
+void function_1(){
+
+ struct rectangle my_rec;
+
+ // 通过 . 来访问结构中的数据
+ my_rec.width = 10;
+ my_rec.height = 20;
+
+ // 你也可以声明指向结构体的指针
+ struct rectangle* my_rec_ptr = &my_rec;
+
+ // 通过取值来改变结构体的成员...
+ (*my_rec_ptr).width = 30;
+
+ // ... 或者用 -> 操作符作为简写
+ my_rec_ptr->height = 10; // Same as (*my_rec_ptr).height = 10;
+}
+
+// 你也可以用typedef来给一个结构体起一个别名
+typedef struct rectangle rect;
+
+int area(rect r){
+ return r.width * r.height;
+}
+
+///////////////////////////////////////
+// 函数指针
+///////////////////////////////////////
+/*
+在运行时,函数本身也被存放到某块内存区域当中
+函数指针就像其他指针一样, 但却可以被用来直接调用函数,
+并且可以被四处传递(就像回调函数那样)
+但是,定义的语法有可能在一开始会有些误解
+
+例子:通过指针调用str_reverse
+*/
+void str_reverse_through_pointer(char * str_in) {
+ // 定义一个函数指针 f.
+ void (*f)(char *); // 签名一定要与目标函数相同
+ f = &str_reverse; // 将函数的地址在运行时赋给指针
+ (*f)(str_in); // 通过指针调用函数
+ // f(str_in); // 等价于这种调用方式
+}
+
+/*
+只要函数签名是正确的,任何时候都能将正确的函数赋给某个函数指针
+为了可读性和简洁性,函数指针经常和typedef搭配使用:
+*/
+
+typedef void (*my_fnp_type)(char *);
+
+// 实际声明函数指针会这么用:
+// ...
+// my_fnp_type f;
+
+```
+
+## 更多阅读
+
+最好找一本 [K&R, aka "The C Programming Language", “C程序设计语言”](https://en.wikipedia.org/wiki/The_C_Programming_Language)
+
+其他一些比较好的资源 [Learn C the hard way](http://c.learncodethehardway.org/book/)
+
+除了这些,多多Google吧
diff --git a/zh-cn/elisp-cn.html.markdown b/zh-cn/elisp-cn.html.markdown
new file mode 100755
index 00000000..d9a8ce35
--- /dev/null
+++ b/zh-cn/elisp-cn.html.markdown
@@ -0,0 +1,340 @@
+---
+language: elisp
+contributors:
+ - ["Bastien Guerry", "http://bzg.fr"]
+translators:
+ - ["Chenbo Li", "http://binarythink.net"]
+filename: learn-emacs-lisp.el
+---
+
+```scheme
+;; 15分钟学会Emacs Lisp (v0.2a) (作者:bzg,https://github.com/bzg 译者:lichenbo,http://douban.com/people/lichenbo)
+;;
+;; 请先阅读Peter Norvig的一篇好文:
+;; http://norvig.com/21-days.html
+;; (译者注:中文版请见http://blog.youxu.info/21-days/)
+;;
+;; 之后安装GNU Emacs 24.3:
+;;
+;; Debian: apt-get install emacs (视具体发行版而定)
+;; MacOSX: http://emacsformacosx.com/emacs-builds/Emacs-24.3-universal-10.6.8.dmg
+;; Windows: http://ftp.gnu.org/gnu/windows/emacs/emacs-24.3-bin-i386.zip
+;;
+;; 更多信息可以在这里找到:
+;; http://www.gnu.org/software/emacs/#Obtaining
+
+;; 很重要的警告:
+;;
+;; 按照这个教程来学习并不会对你的电脑有任何损坏
+;; 除非你自己在学习的过程中愤怒地把它砸了
+;; 如果出现了这种情况,我不会承担任何责任
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; 打开emacs
+;;
+;; 按'q'消除欢迎界面
+;;
+;; 现在请注意窗口底部的那一个灰色长条
+;;
+;; "*scratch*" 是你现在编辑界面的名字。
+;; 这个编辑界面叫做一个"buffer"。
+;;
+;; 每当你打开Emacs时,都会默认打开这个scratch buffer
+;; 此时你并没有在编辑任何文件,而是在编辑一个buffer
+;; 之后你可以将这个buffer保存到一个文件中。
+;;
+;; 之后的"Lisp interaction" 则是表明我们可以用的某组命令
+;;
+;; Emacs在每个buffer中都有一组内置的命令
+;; 而当你激活某种特定的模式时,就可以使用相应的命令
+;; 这里我们使用`lisp-interaction-mode',
+;; 这样我们就可以使用内置的Emacs Lisp(以下简称Elisp)命令了。
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; 分号是注释开始的标志
+;;
+;; Elisp 是由符号表达式构成的 (即"s-表达式"或"s式"):
+(+ 2 2)
+
+;; 这个s式的意思是 "对2进行加2操作".
+
+;; s式周围有括号,而且也可以嵌套:
+(+ 2 (+ 1 1))
+
+;; 一个s式可以包含原子符号或者其他s式
+;; 在上面的例子中,1和2是原子符号
+;; (+ 2 (+ 1 1)) 和 (+ 1 1) 是s式.
+
+;; 在 `lisp-interaction-mode' 中你可以计算s式.
+;; 把光标移到闭括号后,之后按下ctrl+j(以后简写为'C-j')
+
+(+ 3 (+ 1 2))
+;; ^ 光标放到这里
+;; 按下`C-j' 就会输出 6
+
+;; `C-j' 会在buffer中插入当前运算的结果
+
+;; 而`C-xC-e' 则会在emacs最底部显示结果,也就是被称作"minibuffer"的区域
+;; 为了避免把我们的buffer填满无用的结果,我们以后会一直用`C-xC-e'
+
+;; `setq' 可以将一个值赋给一个变量
+(setq my-name "Bastien")
+;; `C-xC-e' 输出 "Bastien" (在 mini-buffer 中显示)
+
+;; `insert' 会在光标处插入字符串:
+(insert "Hello!")
+;; `C-xC-e' 输出 "Hello!"
+
+;; 在这里我们只传给了insert一个参数"Hello!", 但是
+;; 我们也可以传给它更多的参数,比如2个:
+
+(insert "Hello" " world!")
+;; `C-xC-e' 输出 "Hello world!"
+
+;; 你也可以用变量名来代替字符串
+(insert "Hello, I am " my-name)
+;; `C-xC-e' 输出 "Hello, I am Bastien"
+
+;; 你可以把s式嵌入函数中
+(defun hello () (insert "Hello, I am " my-name))
+;; `C-xC-e' 输出 hello
+
+;; 现在执行这个函数
+(hello)
+;; `C-xC-e' 输出 Hello, I am Bastien
+
+;; 函数中空括号的意思是我们不需要接受任何参数
+;; 但是我们不能一直总是用my-name这个变量
+;; 所以我们现在使我们的函数接受一个叫做"name"的参数
+
+(defun hello (name) (insert "Hello " name))
+;; `C-xC-e' 输出 hello
+
+;; 现在我们调用这个函数,并且将"you"作为参数传递
+
+(hello "you")
+;; `C-xC-e' 输出 "Hello you"
+
+;; 成功!
+
+;; 现在我们可以休息一下
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; 下面我们在新的窗口中新建一个名为 "*test*" 的buffer:
+
+(switch-to-buffer-other-window "*test*")
+;; `C-xC-e' 这时屏幕上会显示两个窗口,而光标此时位于*test* buffer内
+
+;; 用鼠标单击上面的buffer就会使光标移回。
+;; 或者你可以使用 `C-xo' 是的光标跳到另一个窗口中
+
+;; 你可以用 `progn'命令将s式结合起来:
+(progn
+ (switch-to-buffer-other-window "*test*")
+ (hello "you"))
+;; `C-xC-e' 此时屏幕分为两个窗口,并且在*test* buffer中显示"Hello you"
+
+;; 现在为了简洁,我们需要在每个s式后面都使用`C-xC-e'来执行,后面就不再说明了
+
+;; 记得可以用过鼠标或者`C-xo'回到*scratch*这个buffer。
+
+;; 清除当前buffer也是常用操作之一:
+(progn
+ (switch-to-buffer-other-window "*test*")
+ (erase-buffer)
+ (hello "there"))
+
+;; 也可以回到其他的窗口中
+(progn
+ (switch-to-buffer-other-window "*test*")
+ (erase-buffer)
+ (hello "you")
+ (other-window 1))
+
+;; 你可以用 `let' 将一个值和一个局部变量绑定:
+(let ((local-name "you"))
+ (switch-to-buffer-other-window "*test*")
+ (erase-buffer)
+ (hello local-name)
+ (other-window 1))
+
+;; 这里我们就不需要使用 `progn' 了, 因为 `let' 也可以将很多s式组合起来。
+
+;; 格式化字符串的方法:
+(format "Hello %s!\n" "visitor")
+
+;; %s 是字符串占位符,这里被"visitor"替代.
+;; \n 是换行符。
+
+;; 现在我们用格式化的方法再重写一下我们的函数:
+(defun hello (name)
+ (insert (format "Hello %s!\n" name)))
+
+(hello "you")
+
+;; 我们再用`let'新建另一个函数:
+(defun greeting (name)
+ (let ((your-name "Bastien"))
+ (insert (format "Hello %s!\n\nI am %s."
+ name ; the argument of the function
+ your-name ; the let-bound variable "Bastien"
+ ))))
+
+;; 之后执行:
+(greeting "you")
+
+;; 有些函数可以和用户交互:
+(read-from-minibuffer "Enter your name: ")
+
+;; 这个函数会返回在执行时用户输入的信息
+
+;; 现在我们让`greeting'函数显示你的名字:
+(defun greeting (from-name)
+ (let ((your-name (read-from-minibuffer "Enter your name: ")))
+ (insert (format "Hello!\n\nI am %s and you are %s."
+ from-name ; the argument of the function
+ your-name ; the let-bound var, entered at prompt
+ ))))
+
+(greeting "Bastien")
+
+;; 我们让结果在另一个窗口中显示:
+(defun greeting (from-name)
+ (let ((your-name (read-from-minibuffer "Enter your name: ")))
+ (switch-to-buffer-other-window "*test*")
+ (erase-buffer)
+ (insert (format "Hello %s!\n\nI am %s." your-name from-name))
+ (other-window 1)))
+
+;; 测试一下:
+(greeting "Bastien")
+
+;; 第二节结束,休息一下吧。
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; 我们将一些名字存到列表中;
+(setq list-of-names '("Sarah" "Chloe" "Mathilde"))
+
+;; 用 `car'来取得第一个名字:
+(car list-of-names)
+
+;; 用 `cdr'取得剩下的名字:
+(cdr list-of-names)
+
+;; 用 `push'把名字添加到列表的开头:
+(push "Stephanie" list-of-names)
+
+;; 注意: `car' 和 `cdr' 并不修改列表本身, 但是 `push' 却会对列表本身进行操作.
+;; 这个区别是很重要的: 有些函数没有任何副作用(比如`car')
+;; 但还有一些却是有的 (比如 `push').
+
+;; 我们来对`list-of-names'列表中的每一个元素都使用hello函数:
+(mapcar 'hello list-of-names)
+
+;; 将 `greeting' 改进,使的我们能够对`list-of-names'中的所有名字执行:
+(defun greeting ()
+ (switch-to-buffer-other-window "*test*")
+ (erase-buffer)
+ (mapcar 'hello list-of-names)
+ (other-window 1))
+
+(greeting)
+
+;; 记得我们之前定义的 `hello' 函数吗? 这个函数接受一个参数,名字。
+;; `mapcar' 调用 `hello', 并将`list-of-names'作为参数先后传给`hello'
+
+;; 现在我们对显示的buffer中的内容进行一些更改:
+
+(defun replace-hello-by-bonjour ()
+ (switch-to-buffer-other-window "*test*")
+ (goto-char (point-min))
+ (while (search-forward "Hello")
+ (replace-match "Bonjour"))
+ (other-window 1))
+
+;; (goto-char (point-min)) 将光标移到buffer的开始
+;; (search-forward "Hello") 查找字符串"Hello"
+;; (while x y) 当x返回某个值时执行y这个s式
+;; 当x返回`nil' (空), 退出循环
+
+(replace-hello-by-bonjour)
+
+;; 你会看到所有在*test* buffer中出现的"Hello"字样都被换成了"Bonjour"
+
+;; 你也会得到以下错误提示: "Search failed: Hello".
+;;
+;; 如果要避免这个错误, 你需要告诉 `search-forward' 这个命令是否在
+;; buffer的某个地方停止查找, 并且在什么都没找到时是否应该不给出错误提示
+
+;; (search-forward "Hello" nil t) 可以达到这个要求:
+
+;; `nil' 参数的意思是 : 查找并不限于某个范围内
+;; `t' 参数的意思是: 当什么都没找到时,不给出错误提示
+
+;; 在下面的函数中,我们用到了s式,并且不给出任何错误提示:
+
+(defun hello-to-bonjour ()
+ (switch-to-buffer-other-window "*test*")
+ (erase-buffer)
+ ;; 为`list-of-names'中的每个名字调用hello
+ (mapcar 'hello list-of-names)
+ (goto-char (point-min))
+ ;; 将"Hello" 替换为"Bonjour"
+ (while (search-forward "Hello" nil t)
+ (replace-match "Bonjour"))
+ (other-window 1))
+
+(hello-to-bonjour)
+
+;; 给这些名字上个色:
+
+(defun boldify-names ()
+ (switch-to-buffer-other-window "*test*")
+ (goto-char (point-min))
+ (while (re-search-forward "Bonjour \\(.+\\)!" nil t)
+ (add-text-properties (match-beginning 1)
+ (match-end 1)
+ (list 'face 'bold)))
+ (other-window 1))
+
+;; 这个函数使用了 `re-search-forward': 和查找一个字符串不同,你用这个命令可以查找一个模式,即正则表达式
+
+;; 正则表达式 "Bonjour \\(.+\\)!" 的意思是:
+;; 字符串 "Bonjour ", 之后跟着
+;; 一组 | \\( ... \\) 结构
+;; 任意字符 | . 的含义
+;; 有可能重复的 | + 的含义
+;; 之后跟着 "!" 这个字符串
+
+;; 准备好了?试试看。
+
+(boldify-names)
+
+;; `add-text-properties' 可以添加文字属性, 比如文字样式
+
+;; 好的,我们成功了!
+
+;; 如果你想对一个变量或者函数有更多的了解:
+;;
+;; C-h v 变量 回车
+;; C-h f 函数 回车
+;;
+;; 阅读Emacs Lisp官方文档:
+;;
+;; C-h i m elisp 回车
+;;
+;; 在线阅读Emacs Lisp文档:
+;; https://www.gnu.org/software/emacs/manual/html_node/eintr/index.html
+
+;; 感谢以下同学的建议和反馈:
+;; - Wes Hardaker
+;; - notbob
+;; - Kevin Montuori
+;; - Arne Babenhauserheide
+;; - Alan Schmitt
+```
+
diff --git a/zh-cn/java-cn.html.markdown b/zh-cn/java-cn.html.markdown
new file mode 100755
index 00000000..4db4e91e
--- /dev/null
+++ b/zh-cn/java-cn.html.markdown
@@ -0,0 +1,404 @@
+---
+
+language: java
+contributors:
+ - ["Jake Prather", "http://github.com/JakeHP"]
+translators:
+ - ["Chenbo Li", "http://binarythink.net"]
+filename: LearnJava.java
+
+---
+
+Java是一个通用的程序语言, 包含并发, 基于类的面向对象等特性
+[阅读更多](http://docs.oracle.com/javase/tutorial/java/index.html)
+
+```java
+// 单行注释
+/*
+多行注释
+*/
+/**
+JavaDoc(Java文档)注释是这样的。可以用来描述类和类的属性。
+*/
+
+// 导入 java.util中的 ArrayList 类
+import java.util.ArrayList;
+// 导入 java.security 包中的所有类
+import java.security.*;
+
+// 每个 .java 文件都包含一个public类,这个类的名字必须和这个文件名一致。
+public class LearnJava {
+
+ // 每个程序都需要有一个main函数作为入口
+ public static void main (String[] args) {
+
+ // 使用 System.out.println 来输出到标准输出
+ System.out.println("Hello World!");
+ System.out.println(
+ "Integer: " + 10 +
+ " Double: " + 3.14 +
+ " Boolean: " + true);
+
+ // 如果要在输出后不自动换行,可以使用System.out.print方法。
+ System.out.print("Hello ");
+ System.out.print("World");
+
+
+ ///////////////////////////////////////
+ // 类型与变量
+ ///////////////////////////////////////
+
+ // 用 <type> <name> 来声明变量
+ // 字节类型 - 8位补码表示
+ // (-128 <= 字节 <= 127)
+ byte fooByte = 100;
+
+ // 短整型 - 16位补码表示
+ // (-32,768 <= 短整型 <= 32,767)
+ short fooShort = 10000;
+
+ // 整型 - 32位补码表示
+ // (-2,147,483,648 <= 整型 <= 2,147,483,647)
+ int fooInt = 1;
+
+ // 长整型 - 64位补码表示
+ // (-9,223,372,036,854,775,808 <= 长整型 <= 9,223,372,036,854,775,807)
+ long fooLong = 100000L;
+ // L可以用来表示一个数字是长整型的。
+ // 其他的数字都默认为整型。
+
+ // 注意:Java中没有无符号类型
+
+ // 浮点型 - 即 IEEE 754 规定的32位单精度浮点类型
+ float fooFloat = 234.5f;
+ // f用来表示一个数字是浮点型的。
+ // 否则会被默认当做是双精度浮点型。
+
+ // 双精度浮点型 - 即 IEEE 754 规定的64位双精度浮点类型
+ double fooDouble = 123.4;
+
+ // 布尔类型 - true 与 false
+ boolean fooBoolean = true;
+ boolean barBoolean = false;
+
+ // 字符类型 - 16位 Unicode编码字符
+ char fooChar = 'A';
+
+ // 用 final 可以使一个常量不可更改
+ final int HOURS_I_WORK_PER_WEEK = 9001;
+
+ // 字符串
+ String fooString = "My String Is Here!";
+
+ // \n 代表一个新的换行
+ String barString = "Printing on a new line?\nNo Problem!";
+ // \t 代表一个新的制表符
+ String bazString = "Do you want to add a tab?\tNo Problem!";
+ System.out.println(fooString);
+ System.out.println(barString);
+ System.out.println(bazString);
+
+ // 数组
+ // 数组在声明时大小必须已经确定
+ // 数组的声明格式:
+ //<数据类型> [] <变量名> = new <数据类型>[<数组大小>];
+ int [] intArray = new int[10];
+ String [] stringArray = new String[1];
+ boolean [] booleanArray = new boolean[100];
+
+ // 声明并初始化数组也可以这样:
+ int [] y = {9000, 1000, 1337};
+
+ // 随机访问数组中的元素
+ System.out.println("intArray @ 0: " + intArray[0]);
+
+ // 数组下标从0开始并且可以被更改
+ intArray[1] = 1;
+ System.out.println("intArray @ 1: " + intArray[1]); // => 1
+
+ // 其他数据类型
+ // ArrayLists - 类似于数组,但是功能更多,并且大小也可以改变
+ // LinkedLists
+ // Maps
+ // HashMaps
+
+ ///////////////////////////////////////
+ // 操作符
+ ///////////////////////////////////////
+ System.out.println("\n->Operators");
+
+ int i1 = 1, i2 = 2; // 多重声明可以简化
+
+ // 算数运算
+ System.out.println("1+2 = " + (i1 + i2)); // => 3
+ System.out.println("2-1 = " + (i2 - i1)); // => 1
+ System.out.println("2*1 = " + (i2 * i1)); // => 2
+ System.out.println("1/2 = " + (i1 / i2)); // => 0 (0.5 truncated down)
+
+ // 取余
+ System.out.println("11%3 = "+(11 % 3)); // => 2
+
+ // 比较操作符
+ System.out.println("3 == 2? " + (3 == 2)); // => false
+ System.out.println("3 != 2? " + (3 != 2)); // => true
+ System.out.println("3 > 2? " + (3 > 2)); // => true
+ System.out.println("3 < 2? " + (3 < 2)); // => false
+ System.out.println("2 <= 2? " + (2 <= 2)); // => true
+ System.out.println("2 >= 2? " + (2 >= 2)); // => true
+
+ // 位运算操作符
+ /*
+ ~ 补
+ << 带符号左移
+ >> 带符号右移
+ >>> 无符号右移
+ & 和
+ ^ 异或
+ | 相容或
+ */
+
+ // 自增
+ int i = 0;
+ System.out.println("\n->Inc/Dec-rementation");
+ System.out.println(i++); //i = 1 后自增
+ System.out.println(++i); //i = 2 前自增
+ System.out.println(i--); //i = 1 后自减
+ System.out.println(--i); //i = 0 前自减
+
+ ///////////////////////////////////////
+ // 控制结构
+ ///////////////////////////////////////
+ System.out.println("\n->Control Structures");
+
+ // If语句和C的类似
+ int j = 10;
+ if (j == 10){
+ System.out.println("I get printed");
+ } else if (j > 10) {
+ System.out.println("I don't");
+ } else {
+ System.out.println("I also don't");
+ }
+
+ // While循环
+ int fooWhile = 0;
+ while(fooWhile < 100)
+ {
+ //System.out.println(fooWhile);
+ //增加计数器
+ //遍历99次, fooWhile 0->99
+ fooWhile++;
+ }
+ System.out.println("fooWhile Value: " + fooWhile);
+
+ // Do While循环
+ int fooDoWhile = 0;
+ do
+ {
+ //System.out.println(fooDoWhile);
+ //增加计数器
+ //遍历99次, fooDoWhile 0->99
+ fooDoWhile++;
+ }while(fooDoWhile < 100);
+ System.out.println("fooDoWhile Value: " + fooDoWhile);
+
+ // For 循环
+ int fooFor;
+ //for 循环结构 => for(<起始语句>; <循环进行的条件>; <步长>)
+ for(fooFor=0; fooFor<10; fooFor++){
+ //System.out.println(fooFor);
+ //遍历 10 次, fooFor 0->9
+ }
+ System.out.println("fooFor Value: " + fooFor);
+
+ // Switch Case 语句
+ // switch可以用来处理 byte, short, char, 和 int 数据类型
+ // 也可以用来处理枚举类型,字符串类,和原始数据类型的包装类:
+ // Character, Byte, Short, 和 Integer
+ int month = 3;
+ String monthString;
+ switch (month){
+ case 1:
+ monthString = "January";
+ break;
+ case 2:
+ monthString = "February";
+ break;
+ case 3:
+ monthString = "March";
+ break;
+ default:
+ monthString = "Some other month";
+ break;
+ }
+ System.out.println("Switch Case Result: " + monthString);
+
+
+ ///////////////////////////////////////
+ // 类型转换
+ ///////////////////////////////////////
+
+ // 数据转换
+
+ // 将字符串转换为整型
+ Integer.parseInt("123");//返回整数123
+
+ // 将整型转换为字符串
+ Integer.toString(123);//返回字符串"123"
+
+ // 其他的数据也可以进行互相转换:
+ // Double
+ // Long
+ // String
+
+ // 类型转换
+ // 你也可以对java对象进行类型转换, 但其中会牵扯到很多概念
+ // 在这里可以查看更详细的信息:
+ // http://docs.oracle.com/javase/tutorial/java/IandI/subclasses.html
+
+
+ ///////////////////////////////////////
+ // 类与函数
+ ///////////////////////////////////////
+
+ System.out.println("\n->Classes & Functions");
+
+ // (Bicycle类定义如下)
+
+ // 用new来实例化一个类
+ Bicycle trek = new Bicycle();
+
+ // 调用对象的方法
+ trek.speedUp(3); // 需用getter和setter方法
+ trek.setCadence(100);
+
+ // toString 可以把对象转换为字符串
+ System.out.println("trek info: " + trek.toString());
+
+ } // main 方法结束
+} // LearnJava 类结束
+
+
+// 你也可以把其他的非public类放入到.java文件中
+
+
+// 类定义的语法:
+// <public/private/protected> class <类名>{
+// //成员变量, 构造函数, 函数
+// //Java中函数被称作方法
+// }
+
+class Bicycle {
+
+ // Bicycle 类的成员变量和方法
+ public int cadence; // Public: 任意位置均可访问
+ private int speed; // Private: 只在同类中可以访问
+ protected int gear; // Protected: 可以在同类与子类中可以访问
+ String name; // default: 可以在包内中可以访问
+
+ // 构造函数是初始化一个对象的方式
+ // 以下是一个默认构造函数
+ public Bi450635425cycle() {
+ gear = 1;
+ cadence = 50;
+ speed = 5;
+ name = "Bontrager";
+ }
+
+ // 一下是一个含有参数的构造函数
+ public Bicycle(int startCadence, int startSpeed, int startGear, String name) {
+ this.gear = startGear;
+ this.cadence = startCadence;
+ this.speed = startSpeed;
+ this.name = name;
+ }
+
+ // 函数语法:
+ // <public/private/protected> <返回值类型> <函数名称>(<参数列表>)
+
+ // Java类中经常会用getter和setter来对成员变量进行操作
+
+ // 方法声明的语法:
+ // <作用域> <返回值类型> <方法名>(<参数列表>)
+ public int getCadence() {
+ retur450635425n cadence;
+ }
+
+ // void返450635425回值函数没有返回值
+ public void setCadence(int newValue) {
+ cadence = newValue;
+ }
+
+ public void setGear(int newValue) {
+ gear = newValue;
+ }
+
+ public void speedUp(int increment) {
+ speed += increment;
+ }
+
+ public void slowDown(int decrement) {
+ speed -= decrement;
+ }
+
+ public void setName(String newName) {
+ name = newName;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ //返回对象属性的方法
+ @Override
+ public String toString() {
+ return "gear: " + gear +
+ " cadence: " + cadence +
+ " speed: " + speed +
+ " name: " + name;
+ }
+} // Bicycle 类结束
+
+// PennyFarthing 是 Bicycle 的子类
+class PennyFarthing extends Bicycle {
+ // (Penny Farthings 是前轮很大的 Bicycle, 并且没有齿轮)
+
+ public PennyFarthing(int startCadence, int startSpeed){
+ // 通过super调用父类的构造函数
+ super(startCadence, startSpeed, 0, "PennyFarthing");
+ }
+
+ // 你可以用@注释来表示需要重载的方法
+ // 了解更多的注释使用方法,可以访问下面的地址:
+ // http://docs.oracle.com/javase/tutorial/java/annotations/
+ @Override
+ public void setGear(int gear) {
+ gear = 0;
+ }
+
+}
+
+```
+
+## 更多阅读
+
+下面的链接只是为了便于大家理解这些主题而给出的,对于具体的例子请大家自行Google
+
+其他主题:
+
+* [Java 官方教程](http://docs.oracle.com/javase/tutorial/index.html)
+
+* [Java 访问修饰符](http://docs.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html)
+
+* [面向对象程序设计概念](http://docs.oracle.com/javase/tutorial/java/concepts/index.html):
+ * [继承](http://docs.oracle.com/javase/tutorial/java/IandI/subclasses.html)
+ * [多态](http://docs.oracle.com/javase/tutorial/java/IandI/polymorphism.html)
+ * [抽象](http://docs.oracle.com/javase/tutorial/java/IandI/abstract.html)
+
+* [异常](http://docs.oracle.com/javase/tutorial/essential/exceptions/index.html)
+
+* [接口](http://docs.oracle.com/javase/tutorial/java/IandI/createinterface.html)
+
+* [泛型](http://docs.oracle.com/javase/tutorial/java/generics/index.html)
+
+* [Java代码规范](http://www.oracle.com/technetwork/java/codeconv-138413.html)
diff --git a/zh-cn/php-cn.html.markdown b/zh-cn/php-cn.html.markdown
new file mode 100755
index 00000000..e3dfe419
--- /dev/null
+++ b/zh-cn/php-cn.html.markdown
@@ -0,0 +1,635 @@
+---
+language: php
+contributors:
+ - ["Malcolm Fell", "http://emarref.net/"]
+ - ["Trismegiste", "https://github.com/Trismegiste"]
+translators:
+ - ["Chenbo Li", "http://binarythink.net"]
+filename: learnphp.php
+---
+
+这份教程所使用的版本是 PHP 5+.
+
+```php
+<?php // PHP必须被包围于 <?php ? > 之中
+
+// 如果你的文件中只有php代码,那么最好省略结束括号标记
+
+// 这是单行注释的标志
+
+# 井号也可以,但是//更常见
+
+/*
+ 这是多行注释
+*/
+
+// 使用 "echo" 或者 "print" 来输出信息到标准输出
+print('Hello '); // 输出 "Hello " 并且没有换行符
+
+// () 对于echo和print是可选的
+echo "World\n"; // 输出 "World" 并且换行
+// (每个语句必须以分号结尾)
+
+// 在 <?php 标签之外的语句都被自动输出到标准输出
+?>Hello World Again!
+<?php
+
+
+/************************************
+ * 类型与变量
+ */
+
+// 变量以$开始
+// 变量可以以字母或者下划线开头,后面可以跟着数字、字母和下划线
+
+// 布尔值是大小写无关的
+$boolean = true; // 或 TRUE 或 True
+$boolean = false; // 或 FALSE 或 False
+
+// 整型
+$int1 = 12; // => 12
+$int2 = -12; // => -12
+$int3 = 012; // => 10 (0开头代表八进制数)
+$int4 = 0x0F; // => 15 (0x开头代表十六进制数)
+
+// 浮点型 (即双精度浮点型)
+$float = 1.234;
+$float = 1.2e3;
+$float = 7E-10;
+
+// 算数运算
+$sum = 1 + 1; // 2
+$difference = 2 - 1; // 1
+$product = 2 * 2; // 4
+$quotient = 2 / 1; // 2
+
+// 算数运算的简写
+$number = 0;
+$number += 1; // $number 自增1
+echo $number++; // 输出1 (运算后自增)
+echo ++$number; // 输出3 (自增后运算)
+$number /= $float; // 先除后赋值给 $number
+
+// 字符串需要被包含在单引号之中
+$sgl_quotes = '$String'; // => '$String'
+
+// 如果需要在字符串中引用变量,就需要使用双引号
+$dbl_quotes = "This is a $sgl_quotes."; // => 'This is a $String.'
+
+// 特殊字符只有在双引号中有用
+$escaped = "This contains a \t tab character.";
+$unescaped = 'This just contains a slash and a t: \t';
+
+// 可以把变量包含在一对大括号中
+$money = "I have $${number} in the bank.";
+
+// 自 PHP 5.3 开始, nowdocs 可以被用作多行非计算型字符串
+$nowdoc = <<<'END'
+Multi line
+string
+END;
+
+// 而Heredocs则可以用作多行计算型字符串
+$heredoc = <<<END
+Multi line
+$sgl_quotes
+END;
+
+// 字符串需要用 . 来连接
+echo 'This string ' . 'is concatenated';
+
+
+/********************************
+ * 数组
+ */
+
+// PHP 中的数组都是关联型数组,也就是某些语言中的哈希表或字典
+
+// 在所有PHP版本中均适用:
+$associative = array('One' => 1, 'Two' => 2, 'Three' => 3);
+
+// PHP 5.4 中引入了新的语法
+$associative = ['One' => 1, 'Two' => 2, 'Three' => 3];
+
+echo $associative['One']; // 输出 1
+
+// 声明为列表实际上是给每个值都分配了一个整数键(key)
+$array = ['One', 'Two', 'Three'];
+echo $array[0]; // => "One"
+
+
+/********************************
+ * 输出
+ */
+
+echo('Hello World!');
+// 输出到标准输出
+// 此时标准输出就是浏览器中的网页
+
+print('Hello World!'); // 和echo相同
+
+// echo和print实际上也属于这个语言本身,所以我们省略括号
+echo 'Hello World!';
+print 'Hello World!';
+
+$paragraph = 'paragraph';
+
+echo 100; // 直接输出标量
+echo $paragraph; // 或者输出变量
+
+// 如果你配置了短标签,或者使用5.4.0及以上的版本
+// 你就可以使用简写的echo语法
+?>
+<p><?= $paragraph ?></p>
+<?php
+
+$x = 1;
+$y = 2;
+$x = $y; // $x 现在和 $y 的值相同
+$z = &$y;
+// $z 现在持有 $y 的引用. 现在更改 $z 的值也会更改 $y 的值,反之亦然
+// 但是改变 $y 的值不会改变 $x 的值
+
+echo $x; // => 2
+echo $z; // => 2
+$y = 0;
+echo $x; // => 2
+echo $z; // => 0
+
+
+/********************************
+ * 逻辑
+ */
+$a = 0;
+$b = '0';
+$c = '1';
+$d = '1';
+
+// 如果assert的参数为假,就会抛出警告
+
+// 下面的比较都为真,不管它们的类型是否匹配
+assert($a == $b); // 相等
+assert($c != $a); // 不等
+assert($c <> $a); // 另一种不等的表示
+assert($a < $c);
+assert($c > $b);
+assert($a <= $b);
+assert($c >= $d);
+
+// 下面的比较只有在类型相同、值相同的情况下才为真
+assert($c === $d);
+assert($a !== $d);
+assert(1 == '1');
+assert(1 !== '1');
+
+// 变量可以根据其使用来进行类型转换
+
+$integer = 1;
+echo $integer + $integer; // => 2
+
+$string = '1';
+echo $string + $string; // => 2 (字符串在此时被转化为整数)
+
+$string = 'one';
+echo $string + $string; // => 0
+// 输出0,因为'one'这个字符串无法被转换为整数
+
+// 类型转换可以将一个类型视作另一种类型
+
+$boolean = (boolean) 1; // => true
+
+$zero = 0;
+$boolean = (boolean) $zero; // => false
+
+// 还有一些专用的函数来进行类型转换
+$integer = 5;
+$string = strval($integer);
+
+$var = null; // 空值
+
+
+/********************************
+ * 控制结构
+ */
+
+if (true) {
+ print 'I get printed';
+}
+
+if (false) {
+ print 'I don\'t';
+} else {
+ print 'I get printed';
+}
+
+if (false) {
+ print 'Does not get printed';
+} elseif(true) {
+ print 'Does';
+}
+
+// 三目运算符
+print (false ? 'Does not get printed' : 'Does');
+
+$x = 0;
+if ($x === '0') {
+ print 'Does not print';
+} elseif($x == '1') {
+ print 'Does not print';
+} else {
+ print 'Does print';
+}
+
+
+
+// 下面的语法常用语模板中:
+?>
+
+<?php if ($x): ?>
+This is displayed if the test is truthy.
+<?php else: ?>
+This is displayed otherwise.
+<?php endif; ?>
+
+<?php
+
+// 用switch来实现相同的逻辑
+switch ($x) {
+ case '0':
+ print 'Switch does type coercion';
+ break; // 在case中必须使用一个break语句,
+ // 否则在执行完这个语句后会直接执行后面的语句
+ case 'two':
+ case 'three':
+ // 如果$variable是 'two' 或 'three',执行这里的语句
+ break;
+ default:
+ // 其他情况
+}
+
+// While, do...while 和 for 循环
+$i = 0;
+while ($i < 5) {
+ echo $i++;
+}; // 输出 "01234"
+
+echo "\n";
+
+$i = 0;
+do {
+ echo $i++;
+} while ($i < 5); // 输出 "01234"
+
+echo "\n";
+
+for ($x = 0; $x < 10; $x++) {
+ echo $x;
+} // 输出 "0123456789"
+
+echo "\n";
+
+$wheels = ['bicycle' => 2, 'car' => 4];
+
+// Foreach 循环可以遍历数组
+foreach ($wheels as $wheel_count) {
+ echo $wheel_count;
+} // 输出 "24"
+
+echo "\n";
+
+// 也可以同时遍历键和值
+foreach ($wheels as $vehicle => $wheel_count) {
+ echo "A $vehicle has $wheel_count wheels";
+}
+
+echo "\n";
+
+$i = 0;
+while ($i < 5) {
+ if ($i === 3) {
+ break; // 退出循环
+ }
+ echo $i++;
+} // 输出 "012"
+
+for ($i = 0; $i < 5; $i++) {
+ if ($i === 3) {
+ continue; // 跳过此次遍历
+ }
+ echo $i;
+} // 输出 "0124"
+
+
+/********************************
+ * 函数
+ */
+
+// 通过"function"定义函数:
+function my_function () {
+ return 'Hello';
+}
+
+echo my_function(); // => "Hello"
+
+// 函数名需要以字母或者下划线开头,
+// 后面可以跟着任意的字幕、下划线、数字.
+
+function add ($x, $y = 1) { // $y 是可选参数,默认值为 1
+ $result = $x + $y;
+ return $result;
+}
+
+echo add(4); // => 5
+echo add(4, 2); // => 6
+
+// $result 在函数外部不可访问
+// print $result; // 抛出警告
+
+// 从 PHP 5.3 起我们可以定义匿名函数
+$inc = function ($x) {
+ return $x + 1;
+};
+
+echo $inc(2); // => 3
+
+function foo ($x, $y, $z) {
+ echo "$x - $y - $z";
+}
+
+// 函数也可以返回一个函数
+function bar ($x, $y) {
+ // 用 'use' 将外部的参数引入到里面
+ return function ($z) use ($x, $y) {
+ foo($x, $y, $z);
+ };
+}
+
+$bar = bar('A', 'B');
+$bar('C'); // 输出 "A - B - C"
+
+// 你也可以通过字符串调用函数
+$function_name = 'add';
+echo $function_name(1, 2); // => 3
+// 在通过程序来决定调用哪个函数时很有用
+// 或者,使用 call_user_func(callable $callback [, $parameter [, ... ]]);
+
+/********************************
+ * 导入
+ */
+
+<?php
+// 被导入的php文件也必须以php开标签开始
+
+include 'my-file.php';
+// 现在my-file.php就在当前作用域中可见了
+// 如果这个文件无法被导入(比如文件不存在),会抛出警告
+
+include_once 'my-file.php';
+// my-file.php中的代码在其他地方被导入了,那么就不会被再次导入
+// 这会避免类的多重定义错误
+
+require 'my-file.php';
+require_once 'my-file.php';
+// 和include功能相同,只不过如果不能被导入时,会抛出错误
+
+// my-include.php的内容:
+<?php
+
+return 'Anything you like.';
+// 文件结束
+
+// Include和Require函数也有返回值
+$value = include 'my-include.php';
+
+// 被引入的文件是根据文件路径或者include_path配置来查找到的
+// 如果文件最终没有被找到,那么就会查找当前文件夹。之后才会报错
+/* */
+
+/********************************
+ * 类
+ */
+
+// 类是由class关键字定义的
+
+class MyClass
+{
+ const MY_CONST = 'value'; // 常量
+
+ static $staticVar = 'static';
+
+ // 属性必须声明其作用域
+ public $property = 'public';
+ public $instanceProp;
+ protected $prot = 'protected'; // 当前类和子类可访问
+ private $priv = 'private'; // 仅当前类可访问
+
+ // 通过 __construct 来定义构造函数
+ public function __construct($instanceProp) {
+ // 通过 $this 访问当前对象
+ $this->instanceProp = $instanceProp;
+ }
+
+ // 方法就是类中定义的函数
+ public function myMethod()
+ {
+ print 'MyClass';
+ }
+
+ final function youCannotOverrideMe()
+ {
+ }
+
+ public static function myStaticMethod()
+ {
+ print 'I am static';
+ }
+}
+
+echo MyClass::MY_CONST; // 输出 'value';
+echo MyClass::$staticVar; // 输出 'static';
+MyClass::myStaticMethod(); // 输出 'I am static';
+
+// 通过new来新建实例
+$my_class = new MyClass('An instance property');
+// 如果不传递参数,那么括号可以省略
+
+// 用 -> 来访问成员
+echo $my_class->property; // => "public"
+echo $my_class->instanceProp; // => "An instance property"
+$my_class->myMethod(); // => "MyClass"
+
+
+// 使用extends来生成子类
+class MyOtherClass extends MyClass
+{
+ function printProtectedProperty()
+ {
+ echo $this->prot;
+ }
+
+ // 方法覆盖
+ function myMethod()
+ {
+ parent::myMethod();
+ print ' > MyOtherClass';
+ }
+}
+
+$my_other_class = new MyOtherClass('Instance prop');
+$my_other_class->printProtectedProperty(); // => 输出 "protected"
+$my_other_class->myMethod(); // 输出 "MyClass > MyOtherClass"
+
+final class YouCannotExtendMe
+{
+}
+
+// 你可以使用“魔法方法”来生成getter和setter方法
+class MyMapClass
+{
+ private $property;
+
+ public function __get($key)
+ {
+ return $this->$key;
+ }
+
+ public function __set($key, $value)
+ {
+ $this->$key = $value;
+ }
+}
+
+$x = new MyMapClass();
+echo $x->property; // 会使用 __get() 方法
+$x->property = 'Something'; // 会使用 __set() 方法
+
+// 类可以是被定义成抽象类 (使用 abstract 关键字) 或者
+// 去实现接口 (使用 implements 关键字).
+// 接口需要通过interface关键字来定义
+
+interface InterfaceOne
+{
+ public function doSomething();
+}
+
+interface InterfaceTwo
+{
+ public function doSomethingElse();
+}
+
+// 接口可以被扩展
+interface InterfaceThree extends InterfaceTwo
+{
+ public function doAnotherContract();
+}
+
+abstract class MyAbstractClass implements InterfaceOne
+{
+ public $x = 'doSomething';
+}
+
+class MyConcreteClass extends MyAbstractClass implements InterfaceTwo
+{
+ public function doSomething()
+ {
+ echo $x;
+ }
+
+ public function doSomethingElse()
+ {
+ echo 'doSomethingElse';
+ }
+}
+
+
+// 一个类可以实现多个接口
+class SomeOtherClass implements InterfaceOne, InterfaceTwo
+{
+ public function doSomething()
+ {
+ echo 'doSomething';
+ }
+
+ public function doSomethingElse()
+ {
+ echo 'doSomethingElse';
+ }
+}
+
+
+/********************************
+ * 特征
+ */
+
+// 特征 从 PHP 5.4.0 开始包括,需要用 "trait" 这个关键字声明
+
+trait MyTrait
+{
+ public function myTraitMethod()
+ {
+ print 'I have MyTrait';
+ }
+}
+
+class MyTraitfulClass
+{
+ use MyTrait;
+}
+
+$cls = new MyTraitfulClass();
+$cls->myTraitMethod(); // 输出 "I have MyTrait"
+
+
+/********************************
+ * 命名空间
+ */
+
+// 这部分是独立于这个文件的
+// 因为命名空间必须在一个文件的开始处。
+
+<?php
+
+// 类会被默认的放在全局命名空间中,可以被一个\来显式调用
+
+$cls = new \MyClass();
+
+
+
+// 为一个文件设置一个命名空间
+namespace My\Namespace;
+
+class MyClass
+{
+}
+
+// (或者从其他文件中)
+$cls = new My\Namespace\MyClass;
+
+//或者从其他命名空间中
+namespace My\Other\Namespace;
+
+use My\Namespace\MyClass;
+
+$cls = new MyClass();
+
+// 你也可以为命名空间起一个别名
+
+namespace My\Other\Namespace;
+
+use My\Namespace as SomeOtherNamespace;
+
+$cls = new SomeOtherNamespace\MyClass();
+
+*/
+
+```
+
+## 更多阅读
+
+访问 [PHP 官方文档](http://www.php.net/manual/)
+
+如果你对最佳实践感兴趣(实时更新) [PHP The Right Way](http://www.phptherightway.com/).
+
+如果你很熟悉善于包管理的语言 [Composer](http://getcomposer.org/).
+
+如要了解通用标准,请访问PHP Framework Interoperability Group's [PSR standards](https://github.com/php-fig/fig-standards).