diff options
| author | Adam Bard <github@adambard.com> | 2013-07-31 22:03:42 -0700 | 
|---|---|---|
| committer | Adam Bard <github@adambard.com> | 2013-07-31 22:03:42 -0700 | 
| commit | 27c0560fdfe7bed63d544f6b58a919fa3e24b46f (patch) | |
| tree | a367f97b1e0506a5e4eff68e1334f8e3057b8912 /zh-cn | |
| parent | f6e87835cf5c1602f5f19c02eebccf325d7bd309 (diff) | |
| parent | 1dd8abaa9d0bbf38e6b21181472d7a8ecdc6e484 (diff) | |
Merge pull request #147 from lichenbo/master-cn
Chinese translated version of c and elisp tutorial
Diffstat (limited to 'zh-cn')
| -rwxr-xr-x | zh-cn/c-cn.html.markdown | 394 | ||||
| -rwxr-xr-x | zh-cn/elisp-cn.html.markdown | 340 | ||||
| -rwxr-xr-x | zh-cn/java-cn.html.markdown | 404 | ||||
| -rwxr-xr-x | zh-cn/php-cn.html.markdown | 635 | 
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). | 
