diff options
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). |