制做插件前如果还不会PHP和MySQL就先看一看吧~
1. PHP简介
PHP是一种易于学习和使用的服务器端脚本语言。只需要很少的编程知识你就能使用PHP建立一个真正交互的WEB站点。本教程并不想让你完全了解这种语言,只是能使你尽快加入开发动态web站点的行列。我假定你有一些HTML(或者HTML编辑器)的基本知识和一些编程思想。
PHP是能让你生成动态网页的工具之一。PHP网页文件被当作一般HTML网页文件来处理并且在编辑时你可以用编辑HTML的常规方法编写PHP。
PHP代表:超文本预处理器(PHP: Hypertext Preprocessor)。PHP是完全免费的,不用花钱,你可以从PHP官方站点(http://www.php.net)自由下载。PHP遵守GNU公共许可(GPL),在这一许可下诞生了许多流行的软件诸如Linux和Emacs。你可以不受的获得源码,甚至可以从中加进你自己需要的特色。PHP在大多数Unix平台,GUN/Linux和微软Windows平台上均可以运行。怎样在Windows环境的PC机器或Unix机器上安装PHP的资料可以在PHP官方站点上找到。安装过程很简单。
1.1 历史
三年前,Rasmus Lerdorf为了创建他的在线简历而创造了\"个人主页工具\"(Personal Home Page Tools)。这是一种非常简单的语言。其后越来越多的人们注意到了这种语言并对其扩展提出了各种建议。在许多人的无私奉献下以及这种语言本身的源代码自由性质,它演变成为一种特点丰富的语言,而且现在还在成长中。
PHP虽然很容易学习,但是速度上比mod_perl(植入web服务器的perl模块)慢。Andy Gutmans和Zeev Suraki是Zend的主要作者。可以去Zend站点(http://www.zend.com)了解更多。
PHP的应用在个人性质的web工程中增长显著。根据Netcraft在1999年10月的报告,有931122个域和321128个IP地址利用PHP技术。
1.2 PHP的先进之处
应用PHP有许多好处。当然已知的不利之处在于PHP由于是开放源码项目,没有什么商业支持,并且由此而带来的执行速度缓慢(直到PHP4之前)。但是PHP的邮件列表很是有用而且除非你正在运行像Yahoo!或者Amazon.com这样的极受欢迎的站点,你不会感觉出PHP的速度与其他的有什么不同。最起码我就没有感觉出来!好了,让我们来看看PHP有那些优点:
- 学习过程
我个人更喜欢PHP的非常简单的学习过程。与Java和Perl不同,你不必把头埋进100多页的文档中努力学习才可以写出一个象样的程序。只要了解一些基本的语法和语言特色,你就可以开始你的PHP编码之旅了。之后你在编码过程中如果遇到了什么麻烦,还可以再去翻阅相关文档。
PHP的语法与C,Perl,ASP或者JSP。对于那些对上述之一的语言较熟悉的人来说,PHP太简单了。相反的,如果你对PHP了解较多,那么你对于其他几种语言的学习都很简单了。
你只需要30分钟就可以将PHP的核心语言特点全部掌握,你可能已经非常了解HTML,甚至你已经知道怎样用编辑设计软件或者手工来制作好看的WEB站点。由于PHP代码能够无障碍的添加进你的站点,在你设计和维护站点的同时,你可以很轻松的加入PHP使得你的站点更加具有动态特性。
- 数据库连接
PHP可以编译成具有与许多数据库相连接的函数。PHP与MySQL是现在绝佳的组合。你还可以自己编写外围的函数取间接存取数据库。通过这样的途径当你更换使用的数据库时,可以轻松的更改编码以适应这样的变化。PHPLIB就是最常用的可以提供一般事务需要的一系列基库。
- 可扩展性
就像前面说的那样,PHP已经进入了一个高速发展的时期。对于一个非程序员来说为PHP扩展附加功能可能会比较难,但是对于一个PHP程序员来说并不困难。
- 面向对象编程
PHP提供了类和对象。基于web的编程工作非常需要面向对象编程能力。PHP支持构造器、提取类等。
- 可伸缩性
传统上网页的交互作用是通过CGI来实现的。CGI程序的伸缩性不很理想,因为它为每一个谠诵械腃GI程序开一个进程。解决方法就是将经常用来编写CGI程序的语言的解释器编译进你的web服务器(比如mod_perl,JSP)。PHP就可以以这种方式安装,虽然很少有人愿意这样以CGI方式安装它。内嵌的PHP可以具有更高的可伸缩性。
- 更多特点
PHP的开发者们为了更适合web编程,开发了许多外围的流行基库,这些库包含了更易用的层。你可以利用PHP连接包括Oracle,MS-Access,Mysql在内的大部分数据库。你可以在苍蝇上画图,编写程序下载或者显示e-mail。你甚至可以完成网络相关的功能。最好的是,你可以选择你的PHP安装版本需要哪些功能。引用Nissan的Xterra的话来说就是PHP可以做到你想让它做到的一切而且无所不能!
1.3 竞争对手:ASP,mod_perl,JSP
我当然不清楚ASP/JSP能做些什么。不过明确的是编写那样的代码有多简单,购买它们会有多昂贵以及它们需要多么昂贵和强大的硬件。如果你有什么中立的观点(比如说没有被SUN和Microsoft的百万美金所影响),请顺便通知我。
据我所知,JSP基于Java,因此Java程序员可以轻松开始编码。ASP只是一个一般的引擎,具有支持多种语言的能力,不过默认的并且是最常用的还是VBScript。
mod_perl与Perl一样强大,只是更快一些。 2. PHP基本注意事项
2.1) Web Server 如何分辨PHP的档案与HTML档案:
要让Web Server 能执行文件中的PHP程式码,文件的副档名,必须是 .php或 .phtml。
2.2) 程式码区域的开始与结束:
为了让Web Server能区分出 PHP的程式码与HTML码,所以,在每段PHP程式码的开头必须加入
复制内容到剪贴板
代码: ,在结尾的地方加
复制内容到剪贴板
代码: ?> 。
2.3) 命令句:
在PHP中,每一个命令句必须以分号
复制内容到剪贴板
代码: ;
作结束。否则会出现问题。
2.4) 变数:
变数是用来储存程式执行时的暂存资料。在PHP中,变数之前必需加
复制内容到剪贴板
代码: $
的符号。另外,PHP内编码的大小写是有差别的,所以在使用变数时,须注意大小写是否一致。PHP是属于 weakly typed的程式语言,对资料型态的规范较鬆,可以不先经宣告变数,就可以直接使用。好处是,程式写起来比较方便,坏处是,程式出问题时,比较难找出错误。
2.5) 程式注解:
PHP使用的注解符号,与C++,Java一样,单行的注解使用
复制内容到剪贴板
代码: //
。//之后同一行所有的文字,都将不被执行。如果要使用多行的注解,可用
复制内容到剪贴板
代码: /* 和
复制内容到剪贴板
代码: */
的注解符号(上下必须对其)。自/*开始到*/之间的所有文字,在执行时都会被乎略。
3. PHP基本程控结构 3.1 摘要:
程式控制结构,分为条件式于回圈两种,提供PHP程式決定判断的基本能力。
3.2 if 命令句: 实例:
复制内容到剪贴板
代码: echo \"if 范例: \"; if($fruit == \"apple\"){
echo '只有當 $fruit 变量等於是 apple 時, 这一行才会出现';
}
echo '
這一行永遠會出现: $fruit = '.$fruit.\"
\"; ?> 3.2.1 实例:复制内容到剪贴板
代码: echo \"if-else 范例: \";
if($fruit == \"apple\"){
echo '<只有当 $fruit 变量等于是 apple 時, 这一行才会出现來'; }else{
echo '只要 $fruit 变量不是 apple 時, 就会出现这一行'; }echo '
我們的水果: $fruit = '.$fruit.\"
\";?> 3.2.2 实例:复制内容到剪贴板
代码: echo \"if-elseif-else 范例: \"; if($fruit == \"apple\"){
echo '只有当 $fruit 变量等於是 apple 時, 這一行才会出现'; }elseif($fruit==\"orange\"){
echo '只有当要 $fruit 变量是 orange 時, 才会出现这一行'; }else{
echo '>其他的, 都会出现这一行';
}echo '
我们的水果: $fruit = '.$fruit.\"
\"; ?> 3.2.3实例: if的另一種用法, 內嵌在其他文件中
复制内容到剪贴板
代码: if($fruit==\"apple\"): ?>
只有当 $fruit 变量等于 apple 時, 这一行才会出现
elseif($fruit==\"orange\"): ?>
只有当 $fruit 变量是 orange 時, 才会出现这一行
其他的, 都会出现这一行
我们的水果: $fruit = =$fruit?> 3.3 switch 命令句:
用以当出于各种条件下选择后出现的结果[可以很好的替换多个if和elseif] 实例:
复制内容到剪贴板
代码: echo \"switch 范例: case 的标签值为常数\"; switch($fruit){ case \"apple\": $myfruit = \"苹果\"; break;
case \"banana\": $myfruit = \"香蕉\"; break;
case \"orange\": $myfruit = \"柳橙\"; break;
case \"guava\": $myfruit = \"石榴\"; break;
case \"pear\": $myfruit = \"梨子\"; break;
default: //default既默认选择
$myfruit = \"西瓜\";
} echo \"你选的是 $myfruit \"; ?> 3.3.1 使用变量 实例:
复制内容到剪贴板
代码: echo \"switch case 的标签值为变数\"; $a = \"apple\"; $b = \"banana\"; $c = \"orange\"; $d = \"guava\"; $e = \"pear\";
switch($fruit){ case $a:
$myfruit = \"苹果\"; break;
case $b:
$myfruit = \"香蕉\"; break;
case $c:
$myfruit = \"柳橙\"; break;
case $d:
$myfruit = \"石榴\"; break;
case $e:
$myfruit = \"梨子\"; break;
default: $myfruit = \"西瓜\";
} echo \"你选的是 $myfruit \"; ?>
3.4 while 回圈:
当 condition 的值为真时,一直执行 { 和 }所包围住的程式区段,直到 condition的值变成假的为止。所以,使用while回圈時,要特別注意,程式区段里的命令句,或?condition 这个运算式本身,必须要能随时更新,让 condition
能变成假的值。 实例:
复制内容到剪贴板
代码: while(condition){ statement 1; statement 2; . .
statement n; } 3.4.1
{ }所包围的程式区段, 改变 while 的 condition 实例:
复制内容到剪贴板
代码: while($i < 10){
echo \"$i 的平方: \".$i * $i.\"
\"; $i++; } ?>
3.4.2 while 的另一种用法, 內嵌在其他文件中 实例:
复制内容到剪贴板
代码:
=$i?> 的平方: =$i * $i?>
3.5 for 回圈:
用法差不多,但还是给点实例吧 实例:
复制内容到剪贴板
代码: for($i = 1; $i < 10; $i++){
echo \"
echo \"\"; ?>
3.5.1 for 的另一种用法, 內嵌在其他文件中 实例:
复制内容到剪贴板
代码:
数字 | 平方 |
=$i?> | =$i * $i?> |
$_GET可以从网址获取变量信息,比如说: http://yoursite.com/index.php?action=haha 那么,PHP档案就可以这样写(把$_GET引用近来):
复制内容到剪贴板
代码: if(PHP_VERSION < '4.1.0') { $_GET = &$HTTP_GET_VARS; }
if(!$register_globals || !$magic_quotes_gpc) { @extract(addslashes($_GET)); }
if($action == 'haha') { echo \"great\"; } ?>
综合小实例:
写一個程式模拟投掷一颗骰子6000次,并记录每每个点数,出现的次数。 实例1: [code] define (\"THROWS\$p1 = 0; $p2 = 0; $p3 = 0; $p4 = 0; $p5 = 0; $p6 = 0;
for($i = 0; $i < THROWS; $i++){ $p = rand(1, 6); switch($p){ case 1: $p1++; break;
case 2: $p2++; break;
case 3: $p3++; break;
case 4: $p4++; break;
case 5: $p5++; break;
case 6: $p6++; break; }
}echo << 复制内容到剪贴板 代码: define (\"THROWS\$p = array(0,0,0,0,0,0,0); for($i = 0; $i < THROWS; $i++){ $points = rand(1, 6); $p[$points]++; }echo << 4. PHP数据类型 PHP支持整数、浮点数、字符串、数组和对象。变量类型通常不由程序员决定而由PHP运行过程决定(真是好的解脱!)。当然,如果你喜欢的话,你也可以使用cast或者函数settype()将某种类型的变量转换成指定的类型。 4.1 数值 数值类型可以是整数或是浮点数。你可以用以下的语句来为一个数值赋值: 复制内容到剪贴板 代码: $a = 1234; # 十进制数 $a = -123; # 负数 $a = 0123; # 八进制数 (等于十进制数的83) $a = 0x12; # 十六进制数(等于十进制数的18) $a = 1.234; # 浮点数\"双精度数\" $a = 1.2e3; # 双精度数的指数形式 字符串 字符串可以由单引号或双引号引出的字段定义。注意不同的是被单引号引出的字符串是以字面定义的,而双引号引出的字符串可以被扩展。而且,在双引号字符串中可以使用反斜杠()在字符串中加入转义序列和转换字符。举例如下: 复制内容到剪贴板 代码: $first = 'Hello'; $second = \"World\"; $full1 = \"$first $second\"; # 产生 Hello World $full2 = '$first $second';# 产生 $first $second $full3=\"01DC studio,.\" 2000 copyright.\" \" ; 请注意最后一行,如果需要在字符串中使用双引号,可以使用反斜杠字符,象该行语句所示。这里的的反斜杠用来使双引号的功能改变。 可以将字符和数字利用运算符号连接起来。字符被转化成数字,利用其最初位置。在PHP手册中有详细的例子。 4.2 数组与哈希表 数组与哈希表以同样的方法被支持。怎样运用取决于你怎样定义它们。你可以用list()或者array()来定义它们,也可以直接为数组赋值。数组的索引从0开始。虽然我在这里没有说明,但是你一样可以轻易的使用数组。 // 一个包含两个元素的数组 $a[0] = \"first\"; $a[1] = \"second\"; $a[] = \"third\"; // 添加数组元素的简单方法 // 现在$a[2]被赋值为\"third\" echo count($a); // 打印出3,因为该数组有3个元素 // 用一个语句定义一个数组并赋值 $myphonebook = array ( \"sbabu\" => \"5348\\"keith\" => \"4829\\"carole\" => \"4533\" ); // 噢,忘了教长吧,让我们添加一个元素 $myphonebook[\"dean\"] = \"5397\"; // 你定义的carale元素错了,让我们更正它 $myphonebook[\"carole\"] => \"4522\" // 我还没有告诉你怎样使用数组的相似支持方式吗?让我们看一看 echo \"$myphonebook[0]\"; // sbabu echo \"$myphonebook[1]\"; // 5348 其他一些对数组或哈希表有用的函数包括sort(),next(),prev()和each()。 4.3 对象 使用new语句产生一个对象: 实例: 复制内容到剪贴板 代码: function do_foo () { echo \"Doing foo.\"; } } $bar = new foo; $bar->do_foo(); ?> 4.4 改变变量类型 在PHP手册中提到:\"PHP不支持(也不需要)直接在声明变量时定义变量类型;变量类型将根据其被应用的情况决定。如果你为变量var赋值为一个字符串,那么它变成了一个字符串。如果你又为它赋了整数值,那么它就变成了整数。\" 复制内容到剪贴板 代码: $foo = \"0\"; // $foo是字符串(ASCII 48) $foo++; // $foo是字符串\"1\" (ASCII 49) $foo += 1; // $foo现在是整数(2) $foo = $foo + 1.3; // $foo是一个双精度数(3.3) $foo = 5 + \"10 Little Piggies\"; // $foo是一个整数(15) $foo = 5 + \"10 Small Pigs\"; // $foo是一个整数(15) 如果想要强行转换变量类型,可以使用与C语言相同的函数settype()。 4.5 变量与常量 在上一帖已经用到了变量,所有变量都是局部变量,为了使得定义的函数中可以使用外部变量,使用global语句。而你要将该变量的作用范围在该函数之内,使用static语句。 实例: 复制内容到剪贴板 代码: $g_var = 1 ; // 全局范围 function test() { global $g_var; // 这样就可以声明全局变量了 } ?> PHP内置了许多已定义的变量。你也可以用define函数定义你自己的常量,比如define(\"CONSTANT\。 4.6 运算符 PHP具有C,C++和Java中的通常见到的运算符。这些运算符的优先权也是一致的。赋值同样使用\"=\"。 4.5.1算术和字符 以下只有一种运算符是有关字符的: 复制内容到剪贴板 代码: $a + $b :加 $a - $b :减 $a * $b :乘 $a / $b :除 $a % $b :取模(余数) $a . $b :字符串连接 4.5.2逻辑和比较 逻辑运算符有: 复制内容到剪贴板 代码: $a || $b :或 $a or $b :或 $a && $b :与 $a and $b :与 $a xor $b :异或 (当$a或$b为true时为true,两者一样时为false) ! $a :非 复制内容到剪贴板 代码: 比较运算符有: $a == $b :相等 $a != $b :不等 $a < $b :小于 $a <= $b :小于等于 $a > $b :大于 $a >= $b :大于等于 与C一样PHP也有三重运算符(?:)。位操作符在PHP同样存在。 优先权 就和C以及Java一样! 4.7 控制流程结构 PHP有着与C一样的流程控制。大部分在上一贴已经解释过,在这儿让大家复习复习~ 4.7.1 if, else, elseif, if(): endif 复制内容到剪贴板 代码: if (表达式一) { . . . } elseif (表达式二) { . . . } else { . . . } // 或者像Python一样 if (表达式一) : . . . . . . elseif (表达式二) : . . . else : . . . endif ; 4.7.2 while, do..while, for 复制内容到剪贴板 代码: while (表达式) { . . . } do { . . . } while (表达式); for (表达式一; 表达式二; 表达式三) { . . . } //或者像Python一样 while (expr) : . . . endwhile ; 4.7.3 switch switch是对多重if-elseif-else结构的最好的替换: 实例: 复制内容到剪贴板 代码: switch ($i) { case 0: print \"i equals 0\"; case 1: print \"i equals 1\"; case 2: print \"i equals 2\"; } 4.7.4 break, continue break中断当前的循环控制结构。 continue被用来跳出剩下的当前循环并继续执行下一次循环。 4.7.5 require, include 就像C中的#include预处理一样。你在require中指定的那个文件将替代其在主文件中的位置。在有条件的引用文件时,可以使用include()。这样就使得你可以将复杂的PHP文件分割成多个文件并且在不同需要时分别引用它们。 4.8 函数 你可以像以下的例子一样定义自己的函数。函数的返回值可以是任何数据类型: 实例: 复制内容到剪贴板 代码: function foo (变量名一, 变量名二, . . . , 变量名n) { echo \"Example function.n\"; return $retval; } 所有PHP代码都可以出现在函数定义中,甚至包括对其他函数和类的定义。函数必须在引用之前定义。 4.9 类 利用类模型建立类。由于较复杂,这里不加解说 实例: 复制内容到剪贴板 代码: class Employee { var $empno; // 员工人数 var $empnm; // 员工姓名 function add_employee($in_num, $in_name) { $this->empno = $in_num; $this->empnm = $in_name; } function show() { echo \"$this->empno, $this->empnm\"; return; } function changenm($in_name) { $this->empnm = $in_name; } } $sbabu = new Employee; $sbabu->add_employee(10,\"sbabu\"); $sbabu->changenm(\"babu\"); $sbabu->show(); 5. PHP函式的应用 函式,是一个的程式码区段,只需撰写一次,就可以让程式的其他部分,藉由呼叫函式的方式,重复使用。通常,函式会接受参数,执行特定的功能,传回程式执行的结果。藉由使用函式,可以节省你的程式开发时间,以及减少程式的臭虫,提高程式的可维护性。 但是,光是把程式码,写成函式,并不会让你的程式变得更好,或是让你的工作变得更轻鬆。你必须学习养成如何撰写好的函式。好的函式,通常有以下的特质: 最好不超过一页:太长的函式,通常不好维护,而且容易发生错误。 函式只执行一个特定的功能:如果,在一个函式裡面,执行多个功能时,通常必须把各功能,再切割成的函式。这样,才可以更模组化,在主程式组合这些功能时,能更有弹性。 好的函式,会有好名字:如果,你无法替你的函式,找出一个好名字的话,通常代表,你对函式的功能,没有具体的认知。自然无法写出好的函式。 我们使用范例,来学习如何撰写函式: 1) 函式的语法。 2) 参数传递。 3) 预设参数。 4) 函式内变数的范围。 5) 使用 include()函式,来建立自己的函式库。 5.1 函式的语法 撰写函式时,在 function保留字之后,接著是使用者自己命名的函式名称。函式名称之后,是由括弧所包含的是要交给函式处理的参数。视情况需要,函式可以接受任何数目的参数,包括不接受任何参数。之后,是由 { 和 }所包含的程式区段。 函式的执行:在主程式呼叫函式之后,自 { 开始由上而下的顺序,一直执行到 }為止或碰到 return 的命令句时结束。 return 可以用来结束函式的执行,return 后面如果有接任何运算式,则会将运算式所得的结果,传回给主程式。 实例: 复制内容到剪贴板 代码: function 函式名称([参数1,参数2, ...参数n]){ 程式码 } 实例: (无参数, 无回转值) 复制内容到剪贴板 代码: function today(){ $ty = date(\"Y\") - 1911; echo ' '.$ty.'年'.date(\"m月d日\"); } today(); ?> 实例: (无参数, 有回转值) 复制内容到剪贴板 代码: function today(){ $ty = date(\"Y\") - 1911; return' '.$ty.'年'.date(\"m月d日\"); } echo today(); ?> 实例: (有参数, 有回转值) 复制内容到剪贴板 代码: function numberOptions($start, $end, $selected){ $option = \"\"; for($i = $start; $i <= $end; $i++){ $list .= \"\"; } return $list; } $yr = date('Y') - 1911; $yr_start = $yr - 5; $yr_end = $yr + 5; $mn = date('m'); $dy = date('d'); $yr_option = numberOptions($yr_start, $yr_end, $yr); $mn_option = numberOptions(1, 12, $mn); $dy_option = numberOptions(1, 31, $dy); ?> 年 月 日 5.2 参数传递 当其他部分的程式码,呼叫函式,以变数当作参数,传递给函式时,实际上函式所接受到的是这个变数的值,所以,在函式中的程式码,如果更改这个变数时,并不会影响到原本程式中的变数。这种参数的传递方式,称之為值的传递。 另一种参数传递的方式,称之為参照的传递。使用这种方式传递参数给函式处理时,当函式更改参数的值,原本程式的变数值也会跟著改变。使用参照传递方式,在函式的定义中,参数之前必须加上 &符号。其他程式,呼叫这个函式时,必须在这个参数使用变数,不可以是其他的运算式(如:常数、定数)。 实例: 复制内容到剪贴板 代码: function add_by_value($value, $increment){ $value += $increment; } function add_by_reference(&$value, $increment){ $value += $increment; } $n = 100; $i = 50; echo '原本 n 的值: '.$n.' echo '值传递之后 n 的值: '.$n.' echo '参照传递之后 n 的值: '.$n.' 5.3 预设参数 函式使用预设参数时,呼叫函式的程式,可以不需要提供这个参数,而使用函式中所定义的参数预设值。 使用预设参数时,预设参数必须放在非预设参数的后面(右边)。 实例: 复制内容到剪贴板 代码: function numberOptions($start, $end, $selected=3){ $option = \"\"; for($i = $start; $i <= $end; $i++){ $list .= \"\"; } return $list; } $number_options = numberOptions(1, 10); ?> 5.4 函式内变数的范围 函式内所使用的变数,除非特别指定,均為区域变数。区域变数的范围,只限定在定义这个变数的函式内。函式外即使有同名的变数,因為范围不同,所以是另一个变数。两者不会互相影响。 如果,在函式之内有特别指定变数范围(在变数名称之前,加上 global 保留字)。变数变成全域变数。 实例: 复制内容到剪贴板 代码: function local_scope(){ $x = 5; } function global_scope(){ global $x; $x = 10; } $x = 0; echo '原本 x 的值: '.$x.' echo '呼叫 local_scope()函式之後, x 的值: '.$x.' echo '呼叫 global_scope()函式之後, x 的值: '.$x.' 5.5 使用 include() 函式,來建立自己的函式库 到目前为止,所有的函式,都是写在和主程式同一个网页中,所以,只有这个主程式的网页可以呼叫这些函式。 更好的做法,是把所有函式按照功能的类别,写在同一个档案。然后,在主程式中,使用 include() 或 include_once() 函式,将函式的档案,含括在主程式中。透过含括档案的方式,就可以把函式的功能,提供给其他的PHP网页程式使 用。 实例: (使用含括档案的方式) 复制内容到剪贴板 代码: // 档名: 110_07.php function numberOptions($start, $end, $selected){ $option = \"\"; for($i = $start; $i <= $end; $i++){ $list .= \"\"; } return $list; } ?> // 档名: 110_08.php include(\"110_07.php\"); $yr = date('Y') - 1911; $yr_start = $yr - 5; $yr_end = $yr + 5; $mn = date('m'); $dy = date('d'); $yr_option = numberOptions($yr_start, $yr_end, $yr); $mn_option = numberOptions(1, 12, $mn); ?> 年 月 日 6. PHP物体导向程式设计 PHP 支援物件导向程式设计,虽然就纯粹的物件导向程式设计的观点来看,它的支援并不是很完整,但是,只要我们遵循良好的程式设计习惯,我们还是可以善用 PHP ,来开发物件导向的程式。 I 为什么要使用物件导向的程式设计? 在物件导向程式设计的观念提出之前,软体开发者,大多是使用结构化的程式设计。所谓结构化的程式设计,就是把 问题切割成各个比较小的问题,比较小的问题,如果还是复杂到无法以一个函式来解决时,就在切割成为更小的问题。直到可以用一个单一的函式来解决为止。每个函式处理个别的功能,主程式藉由呼叫各个函式,来完成他的工作。 在上一个帖子函式的应用,我们应用了结构化的程式设计,将留言版的功能分割成各个函式,各网页藉由呼叫各函式的方式,完成存取留言版资料的工作。使用结构化的程式设计,的确简化了我们撰写程式的工作,也提高了程式的可维护性。但是,结构化程式设计在开发大型专案时,还是无可避免的碰到了他的瓶颈。因为,结构化的程式设计,专注于功能面(函式)的开发,而往往忽略了功能所要处理的资料。被处理的资料与功能在结构化的程式设计是分离的关系。在大型专案的开发上,由于要处理的问题,相对的要复杂许多,如果,资料与函式之间没有关联性,很容易发生错误,维护起来也很不方便。后来,物件导向程式设计的兴起,就是为了解决,结构化程式设计所面临的资料与功能分离的问题。 II 物件导向程式设计的常用名词: i)属性(Property):即物件里的资料(变数)。 ii)方法(Method):即物件里的功能(函式)。 iii)成员(Member):即类别里所定义的变数或函式。 iv)物件:类别的实例。 v)类别:物件的定义。由使用者所定义的资料型态。 III 物件导向程式设计的支柱 物件导向程式设计的三大支柱,称之为 PIE(Polymorphism多变, Inheritance继承, Encapulation封装)。由于,PHP目前的版本只支援继承及封装,所以,我们在此,仅讨论继承与封装。 所谓封装,就是把功能与资料包装起来成为一个物件,并定义物件的介面。让外界的程式,透过物件所提供的介面,来与这个物件沟通。外界的使用者,无须知道,物件内部如何执行他的作业。只需要知道,如何使用物件的介面,来完成自己的工作即可。所以,设计物件的开发者,日后要更新物件的程式时,只要维持物件的介面不变,便可以确保,使用这物件的外部程式,不需要改写,一样可以执行。而外界程式的开发者,只要遵循不直接存取物件内部的功能及资料,仅透过介面来使用物件的规则,便可以确保程式执行无误。 所谓继承,就是子类别藉由继承父类别的方式,取得父类别所定义的属性及方法。通常,父类别会定义通用的属性及方法,而子类别则延伸父类别定义特定的属性及方法,以解决特定的问题。 IV 如何使用物件导向程式设计来开发程式 使用物件导向的方式来开发程式,最主要的关键,在于程式设计观念的改变。之前,我们使用函式来开发留言版的时候,我们著重在于找出留言版应该具有的功能,然后,按照功能来撰写对应的函式。外界的网页程式,把资料餵给这些功能,来完成它的工作。使用物件导向程式设计时,我们必须把程式所企图解决的问题,看做是一个的个体。在这个个体中,包含了它应该处理的资料,以及处理这些资料的功能。这些功能是为了处理这些资料所產生的。所以,在撰写留言版的程式时,我们要把留言版当作是一个自给自足的个体。把程式所要解决的问题,定义成为个别的个体, 这个过程称之为抽象化(Abstraction)。 当我们的脑子里,有了这个个体所需要的资料以及功能后,我们就可以专注于定义这个个体的类别。把个体的资料,定义成类别的属性;把个体的功能,定义成类别的方法。在定义类别时,先别管外界的程式如何运作,全心全力专注于如何按照这个个体的枨螅写好这个类别。类别定义完之后,外界的程式,便可藉由物件变数,来使用这个我们定义的类?使用者定义的资料型态)。物件导向程式设计,名称上虽然是物件,但是,实际上,程式设计师大部分的心力,在于找出问题中的个体,定义这个个体的类别。使用这类别的程式部分,反而花的时间不多。 在此帖中,我们将使用实际的例子,来实作 PHP的物件导向程式设计。 PHP 物件导向程式设计实例演练 说明: 我们使用范例,来撰写类别: i)类别的语法结构。 ii)封装:定义属性及方法。 iii)使用物件:类别的实例化。 iv)继承。 1. 类别的语法结构 复制内容到剪贴板 代码: class 类别名称 [extends][父类别名称]{ 类别的定义 } 说明: i)定义类别时,在 class 保留字之后,是使用者所定义的类别名称。 ii)如果,所定义的类别要继承其他类别时,需加上 extends 保留字,然后,加上父类别的名称。否则,省略 extends和父类别名称。 iii)之后是由 { 和 }所包围的类别定义。在这里,类别的定义,包括了属性及方法。 2. 封装:定义属性及方法。 复制内容到剪贴板 代码: class 类别名称 [extends][父类别名称]{ // 属性的定义 var $变数名称; // 方法的定义 function 方法名称([参数列]){ } } 说明: i)定义类别的个别属性时,前面必须加 var 保留字。代表这变数是这个类别的属性。 ii)定义属性时,可以给初始值。 iii)定义方法时,规则同函式。 iv)在方法中,如果要存取类别的属性时,必须用 $this->变数名称 这个格式。变数名称在这裡,不可以加 $符号。 v)如果,类别中的方法名称与类别名称相同时,这个方法称之為这个类别的建构方法。建构方法在类别被实例化时执行。类别实例化,说白一点,就是在外界的程式中,產生这个类别的物件变数。 实例: (定义类别) 复制内容到剪贴板 代码: /* 档名:111_01.php 定义 Dog 类别 */ class Dog{ var $food = '骨头'; var $name; function Dog(){ echo '產生 Dog 类别的物件时,便会呼叫这个方法(建构方法)'; } function Eat(){ echo $this->name.'吃'.$this->food; } } ?> 3. 使用物件:类别的实例化。 复制内容到剪贴板 代码: // 产生物件时 $物件变数名称 = new 类别名称; // 呼叫物件方法或存取属性时 $物件变数名称->物件的方法或属性; 说明: i)要产生物件时,必须以一个变数来存放物件。 ii)必须使用 new 保留字来产生物件。产生物件时,会执行这个物件的建构方法。 iii)存取物件的属性或呼叫物件方法时,物件与其成员之间,必须加 ->。 iv)物件的属性之前,不可加 $ 符号。 实例: (使用物件) 复制内容到剪贴板 代码: 档名:111_02.php 使用 Dog 类别 */ // 含括 111_01.php 定义 Dog 类别的PHP档 include_once('111_01.php'); // 产生 Dog 类别的物件 $mydog = new Dog; $mydog->name = '来福'; echo ' i)当子类别继承父类别时,子类别取得父类别所有的成员(属性及方法)。 ii)在子类别的方法,要呼叫父类别的方法时,使用 $this->父类别的方法名称。 iii)父类别通常只定义通用的成员。 iv)子类别延伸父类别原有的功能,可另行定义专属于子类别的功能。 v)当父类别的成员改变时,子类别的成员跟著改变。所以,藉著继承的关系,可以让我们的程式维护性大為提高。 实例: 复制内容到剪贴板 代码: 档名:111_03.php 定义 Pet, Dog, Cat 类别 */ class Pet{ var $food; var $name; var $language; function Pet(){ echo '产生 Pet 类别的物件时,便会呼叫这个方法(建构方法)'; } function Eat(){ echo $this->name.'吃'.$this->food; } function Speak(){ echo $this->name.'说'.$this->language; } } class Dog extends Pet{ function Dog(){ $this->food = '骨头'; $this->language = '汪汪'; echo '产生 Dog 类别的物件时,便会呼叫这个方法(建构方法)'; } } class Cat extends Pet{ function Cat(){ $this->food = '鱼'; $this->language = '喵喵'; echo '产生 Cat 类别的物件时,便会呼叫这个方法(建构方法) function showFear(){ echo $this->name.'怕水'; } } ?> 复制内容到剪贴板 代码: /* 档名:111_04.php 使用 Dog, Cat 类别 */ // 含括 111_03.php 定义 Pet, Dog, Cat 类别的PHP档 include_once('111_03.php'); // 产生 Dog 类别的物件 $mydog = new Dog; $mydog->name = '来福'; echo ' $mycat->showFear(); ?> 7. MySQL 基本 I MySQL简介 什么是MySQL?MySQL是小型企业或者个人网站用来储存资料的资料库,或称数据库。 学习更多的MYSQL资料 http://dev.mysql.com/doc/refman/5.1/zh/index.html II 为何使用MySQL? 一般上,大部分PHP网战都选择与MySQL一同使用,那是因为MySQL与PHP结合不仅简易,而且效率高。MySQL本身也是一个效率高、速度快的数据库,所以一般上我们选用MySQL。 0. 类型解释 smallint 16 位元的整数。 interger 32 位元的整数。 decimal(p,s) p 精确值和 s 大小的十进位整数,精确值p是指全部有几个数(digits)大小值,s是指小数 点後有几位数。如果没有特别指定,则系统会设为 p=5; s=0 。 float 32位元的实数。 double 位元的实数。 char(n) n 长度的字串,n不能超过 2。 varchar(n) 长度不固定且其最大长度为 n 的字串,n不能超过 4000。 graphic(n) 和 char(n) 一样,不过其单位是两个字元 double-bytes, n不能超过127。这个形态是为 了支援两个字元长度的字体,例如中文字。 vargraphic(n) 可变长度且其最大长度为 n 的双字元字串,n不能超过 2000。 date 包含了 年份、月份、日期。 time 包含了 小时、分钟、秒。 timestamp 包含了 年、月、日、时、分、秒、千分之一秒。 1. 建立数据表 注意: 不包括 { 和 } 复制内容到剪贴板 代码: CREATE TABLE `{数据表名}` ( `{字段名1}` 类型 {NOT NULL 或 NULL} default '{起始值}', `{字段名2}` 类型 {NOT NULL 或 NULL} default '{起始值}', `{字段名3}` 类型 {NOT NULL 或 NULL} default '{起始值}', `{字段名4}` 类型 {NOT NULL 或 NULL} default '{起始值}' ) ENGINE={储存引擎} DEFAULT CHARSET={编码}; 实例: 复制内容到剪贴板 代码: CREATE TABLE `cdb_testing` ( `na` varchar(50) NOT NULL default '', `pr` int(10) NOT NULL default '0', `si` int(10) NOT NULL default '0', `fsi` int(10) NOT NULL default '0', `f` varchar(50) NOT NULL default '', `gar` varchar(255) NOT NULL default '', `p` int(1) NOT NULL default '2', `at` int(10) NOT NULL default '1', `pro` int(10) NOT NULL default '100' ) ENGINE=MyISAM DEFAULT CHARSET=gbk; 2. 删除数据表 注意: 不包括 { 和 } 复制内容到剪贴板 代码: DROP TABLE `{数据表名}` 实例: 复制内容到剪贴板 代码: DROP TABLE `cdb_testing` 3. 覆盖原有数据表 注意: 不包括 { 和 } 复制内容到剪贴板 代码: DROP TABLE IF EXISTS `{数据表名}`; CREATE TABLE `{数据表名}` ( `{字段名1}` 类型 {NOT NULL 或 NULL} default '{起始值}', `{字段名2}` 类型 {NOT NULL 或 NULL} default '{起始值}', `{字段名3}` 类型 {NOT NULL 或 NULL} default '{起始值}', `{字段名4}` 类型 {NOT NULL 或 NULL} default '{起始值}' ) ENGINE={储存引擎} DEFAULT CHARSET={编码}; 查看存储类型 http://dev.mysql.com/doc/refman/5.1/zh/storage-engines.html#myisam-storage-engine 实例: 复制内容到剪贴板 代码: DROP TABLE IF EXISTS `cdb_testing`; CREATE TABLE `cdb_testing` ( `na` varchar(50) NOT NULL default '', `pr` int(10) NOT NULL default '0', `si` int(10) NOT NULL default '0', `fsi` int(10) NOT NULL default '0', `f` varchar(50) NOT NULL default '', `gar` varchar(255) NOT NULL default '', `p` int(1) NOT NULL default '2', `at` int(10) NOT NULL default '1', `pro` int(10) NOT NULL default '100' ) ENGINE=MyISAM DEFAULT CHARSET=gbk; 5. Discuz! 插件区的一些数据库工具 5.1 多论坛数据库合并工具[Database Merger] For DZ4.1 http://www.discuz.net/viewthread ... hlight=%CA%FD%BE%DD 5.2 数据库编码管理工具 For D3/4/5 http://www.discuz.net/viewthread ... hlight=%CA%FD%BE%DD 5.3 数据库管理器 for 4.1 http://www.discuz.net/viewthread ... hlight=%CA%FD%BE%DD 5.4 PerfectWorks[非卖品]让数据不再?????的数据库升级工具 http://www.discuz.net/viewthread ... hlight=%CA%FD%BE%DD 5.5 MYSQL数据库编码转换、数据导入恢复工具! http://www.discuz.net/viewthread ... hlight=%CA%FD%BE%DD 8. MySQL: SQL 基本语法 I 现在将承接上面的,我们现在将使用更多种SQL语法 II下面介绍的语法是在 Discuz! 后台和 数据库工具 升级数据库时能用到的,至于 SELECT 语法,会在下一帖讨论 1. 在原有数据表中加入字段 1.1 多数据表 注意:不包括 { 和 } 复制内容到剪贴板 代码: ALTER TABLE `{数据表名}` ADD `{字段名1}` 类型 DEFAULT '{起始值}' {NOT NULL 或 NULL}; ALTER TABLE `{数据表名1}` ADD `{字段名2}` 类型 DEFAULT '{起始值}' {NOT NULL 或 NULL}; ALTER TABLE `{数据表名2}` ADD `{字段名3}` 类型 DEFAULT '{起始值}' {NOT NULL 或 NULL}; 实例: 复制内容到剪贴板 代码: ALTER TABLE `cdb_te` ADD `tts` INT( 8 ) DEFAULT '1' NOT NULL; ALTER TABLE `cdb_test` ADD `ton` INT( 10 ) DEFAULT '1' NOT NULL; ALTER TABLE `cdb_testiing` ADD `tgt` VARCHAR( 1 ) DEFAULT '1' NOT NULL; 1.2 单数据表 注意:不包括 { 和 } 复制内容到剪贴板 代码: ALTER TABLE `{数据表名}` ADD `{字段名1}` 类型 DEFAULT '{起始值}' {NOT NULL 或 NULL} , ADD `{字段名2}` INT( 8 ) 类型 DEFAULT '{起始值}' {NOT NULL 或 NULL} , ADD `{字段名3}` INT( 8 ) 类型 DEFAULT '{起始值}' {NOT NULL 或 NULL} , ADD `{字段名4}` INT( 8 ) 类型 DEFAULT '{起始值}' {NOT NULL 或 NULL} ; 实例: 复制内容到剪贴板 代码: ALTER TABLE `cdb_test` ADD `oic` INT( 8 ) NOT NULL , ADD `ar` INT( 8 ) DEFAULT '0' NOT NULL , ADD `cr` INT( 8 ) DEFAULT '1' NOT NULL , ADD `ge` INT( 8 ) DEFAULT '2' NOT NULL , ADD `au` VARCHAR( 10 ) DEFAULT 'test' NOT NULL ; 1.3 更改字段设置 注意:不包括 { 和 } 复制内容到剪贴板 代码: ALTER TABLE `{数据表名}` CHANGE `{原有字段名}` `{新的字段名(可保留原有)}` {新的类型(可保留原有)} DEFAULT '{新的起始值(一样可保留)}' {NOT NULL 或 NULL}; 实例: 复制内容到剪贴板 代码: ALTER TABLE `cdb_te` CHANGE `tts` `ttsg` INT( 9 ) DEFAULT '32' NOT NULL; 2. 在原有数据表中删除字段 2.1 多数据表 注意:不包括 { 和 } 复制内容到剪贴板 代码: ALTER TABLE `{数据表名}` DROP `{字段名1}`; ALTER TABLE `{数据表名1}` DROP `{字段名2}`; ALTER TABLE `{数据表名2}` DROP `{字段名3}`; 实例: 复制内容到剪贴板 代码: ALTER TABLE `cdb_te` DROP `tts`; ALTER TABLE `cdb_test` DROP `ton`; ALTER TABLE `cdb_testiing` DROP `tgt`; 2.2 单数据表 注意:不包括 { 和 } 复制内容到剪贴板 代码: ALTER TABLE `{数据表名}` DROP `{字段名1}` , DROP `{字段名2}` , DROP `{字段名3}` , DROP `{字段名4}` ; 实例: 复制内容到剪贴板 代码: ALTER TABLE `cdb_test` DROP `oic` , DROP `ar` , DROP `cr` , DROP `ge` , DROP `au` ; 3. 更新某一字段的值 3.1 更新所有资料。 注意:不包括 { 和 } 复制内容到剪贴板 代码: UPDATE `{数据表名}` SET `{字段名1}`= '{新的值1}', `{字段名2}` = '{新的值2}' 实例: 复制内容到剪贴板 代码: UPDATE `cdb_test` SET `ton`= '2', `ar` = '5' 说明: i)升级了这句语法后,cdb_test 中 的 ton 字段数值就变为 2 , ar 字段数值就变为 5 了 ii)执行这个句型的命令,会更新资料表中所有的纪录。 iii)使用 UPDATE 更新资料时,一定要指定所要更新的字段以及更新的值。 iv)如果更新的字段超过一个时,每组字段=值,必须以逗号区隔。 3.2 更新特定资料。 注意:不包括 { 和 } 复制内容到剪贴板 代码: UPDATE `{数据表名}` SET `{字段名1}`= '{新的值1}', `{字段名2}`= '{新的值2}' WHERE {条件} 实例: 复制内容到剪贴板 代码: UPDATE `cdb_test` SET `ton`= '2', `ar` = '5' WHERE ge<9 说明: i)要更新特定资料时,可以在后面加上 WHERE条件子句,来限定要更改的纪录。 4. 添加字段的值 注意:不包括 { 和 } 复制内容到剪贴板 代码: INSERT INTO `{数据表名}` (`{字段名1}`, `{字段名2}`, `{字段名3}`) VALUES ('{值1}', '{值2}', '{值3}'); 实例: 复制内容到剪贴板 代码: INSERT INTO `cdb_testing` (`ton`, `ar`, `kg`) VALUES ('qut', '1', '99'); 说明: 值1 为 字段名1 所添加的值 值2 为 字段名2 所添加的值 值3 为 字段名3 所添加的值 5. 删除数据表中的纪录 5.1 删除所有纪录 注意:不包括 { 和 } 复制内容到剪贴板 代码: DELETE FROM `{数据表名}` 实例: 复制内容到剪贴板 代码: DELETE FROM `cdb_test` 说明: i)执行这个句型的命令,会删除资料表中所有的纪录。 5.2 刪除特定資料。 注意:不包括 { 和 } 复制内容到剪贴板 代码: DELETE FROM `{数据表名}` WHERE `{字段名1}` = '{值1}' AND `{字段名2}` = '{值2}' AND `{字段名3}` = '{值3}'; 实例: 复制内容到剪贴板 代码: DELETE FROM `cdb_settings` WHERE `ton` = 'qut' AND `ar` = '1' AND `kg` = '99'; 说明: i)要删除特定资料时,可以在后面加上 WHERE 条件子句,来限定要删除的纪录。 其他SQL相关: http://www.discuz.net/thread-337688-1-1.html http://www.discuz.net/viewthread ... page%3D1&page=2 实用手册 http://www.discuz.net/thread-378437-1-1.html 9. PHP 与 MySQL 结合 我们在本帖将初步探讨 PHP 与 MySQL 的结合 1. SELECT 字句 说明: SELECT 句型,是用来对资料库作查询之用。资料库在执行 SELECT 命令之后,会传回查询的结果。以下分别介绍各种 SELECT 句型的用法: i)基本句型 i)万用字元 iii)使用 WHERE 子句,作為过滤查询的条件。 [上一帖已经稍微解释过,这里再深入解释] iv)使用 ORDER BY 子句,来定义排序的栏位,以及排序的方式。 v)使用 LIMIT 子句,设定查询结果的范围。 1.1 基本句型 注: 不包括 { 和 } 复制内容到剪贴板 代码: SELECT {字段名1}, {字段名2}, {字段名3}, ……{字段名N} FROM {数据表名}; 说明: i)上面的句型,表示选取资料表中所有纪录,并按照:栏位 1, 栏位 2, ...,栏位N的方式,分栏位排列查询的资料。 ii)每个栏位以逗号区隔。 iii)句型中的 SELECT 和 FROM 都是 SQL 的保留字。 iv)SQL 语法,除了资料表名称及栏位名称之外,并不区隔字母的大小写。所以,你也可以写成:Select 栏位 1, 栏位 2, ...,栏位N from 资料表。 实例: 复制内容到剪贴板 代码: SELECT m.adminid, p. authorid, mf.uid FROM cdb_threads; 1.2 万用子元 注: 不包括 { 和 } 复制内容到剪贴板 代码: SELECT * FROM {数据表名} 说明: i)星号 * ,代表所有栏位。 ii)如果需要显示所有栏位时,一一输入栏位名称的方式,不但麻烦,而且容易因為输入错误,而产生问题。所以,使用星号可以简化我们撰写 SELECT 命令的工作。 1.3 WHERE 字句 注: 不包括 { 和 } 复制内容到剪贴板 代码: SELECT {字段名1}, {字段名2}, {字段名3} FROM {数据表名} WHERE {条件} 说明: i)WHERE子句,用来定义查询所要过滤的条件。 ii)只有符合 WHERE 子句条件的纪录,才会被选取。 iii)条件的内容,通常是以栏位来比对某特定的值。要特别注意的是,如果,被比对的值,其资料型态不是数值时,前后必须使用单引号框住。 iv)以下是常用的比较运算符: 运算符 = 意义 等于 != 或 <> 不等于 > >= < <= LIKE 大于 大于等于 小于 小于等于 字串的样式比对。可用%万用字元。 v)WHERE子句中的条件,可以用 AND、OR、NOT等逻辑运算子,来组合成更复杂的查询条件。 vi)条件中的栏位,不一定要出现在 SELECT 的栏位中。 1.4 ORDER BY 子句 注: 不包括 { 和 } 复制内容到剪贴板 代码: SELECT {字段名} FROM {数据表名} {WHERE 子句} ORDER BY {字段名} {排序方式}; 说明: i)ORDER BY 后面必须接字段,表示使用这个字段来排序。 ii)排序方式有两种:昇幂 (ASC),和降幂(DESC)。 iii)如果未指定排序方式时,预设是昇幂的排序。 iv)字段名可以用数据表的栏位名称,使用字段名称时,这个字段不一定要出现在 SELECT 所列出来的栏位中。 v)字段也可以用数字来表示。这个数字是 SELECT 所列出来的字段顺序,起始值为 1。 vi)WHERE 字句可加也可不加 实例: 复制内容到剪贴板 代码: SELECT ar FROM cdb_testing WHERE gm>1 ORDER BY gg DESC; 10. 与 Discuz! 结合 插件设计相关 http://www.discuz.net/usersguide/plugins_design.htm 因篇幅问题不能全部显示,请点此查看更多更全内容
END; ?> 实例2:点数 次数 1 $p1 2 $p2 3 $p3 4 $p4 5 $p5 6 $p6
END; ?>点数 次数 1 $p[1] 2 $p[2] 3 $p[3] 4 $p[4] 5 $p[5] 6 $p[6]
'; add_by_value($n, $i);
'; add_by_reference($n, $i);
'; ?>
'; local_scope();
'; global_scope();
'; ?>
'; $mydog->Eat(); ?> 4. 续承 说明:
'; $this->Pet(); }
'; $mydog->Eat(); echo '
'; $mydog->Speak(); echo '
'; $mycat = new Cat; echo '
'; $mycat->Eat(); echo '
'; $mycat->Speak(); echo '
';
Copyright © 2019- kqyc.cn 版权所有 赣ICP备2024042808号-2
违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com
本站由北京市万商天勤律师事务所王兴未律师提供法律服务