程序中对象传递与普通变量的区别
<script type="text/javascript"> var student1 = { name : 123 }; var student2 = student1; student1.name = 234; alert(student2.name); //alert 234 </script>在PHP中,如下:
<?php // example one class Student{ public $age = 0; } $student1 = new Student(); $student1->age = 2; fun($student1); echo $student1->age; //echo 3; function fun($obj){ $obj->age = 3; } //example two $student2 = $student1; $student2->age = 10; echo $student1->age; //echo 10 ?>在Java中,如下:
public class Student{ public int age = 0; public static void main(String[] args) { Student student1 = new Student(); Student student2 = student1; student1.age = 10; System.out.print(student2.age); //print 10 } }
PHP include require 深入浅出
include() 语句包括并运行指定文件。以下文档也适用于 require()。
以下内容引用自官方文档
1> 这两种结构除了在如何处理失败之外完全一样。include() 产生一个警告而 require() 则导致一个致命错误。换句话说,如果你想在遇到丢失文件时停止处理页面就用 require()。include() 就不是这样,脚本会继续运行。同时也要确认设置了合适的 include_path。注意在 PHP 4.3.5 之前,包含文件中的语法错误不会导致程序停止,但从此版本之后会。
2> 寻找包含文件的顺序先是在当前工作目录的相对的 include_path 下寻找,然后是当前运行脚本所在目录相对的 include_path 下寻找。例如 include_path 是 .,当前工作目录是 /www/,脚本中要 include 一个 include/a.php 并且在该文件中有一句 include "b.php",则寻找 b.php 的顺序先是 /www/,然后是 /www/include/。如果文件名以 ./ 或者是 ../ 开始,则只在当前工作目录相对的 include_path 下寻找。
注释:如果 访问地址是 http://localhost/test/a.php 那么当前工作目录是test/ ,一般程序中建议使用./ 包含文件,这样程序执行起来比较快捷
3> 当一个文件被包括时,其中所包含的代码继承了 include 所在行的变量范围。从该处开始,调用文件在该行处可用的任何变量在被调用的文件中也都可用。不过所有在包含文件中定义的函数和类都具有全局作用域。
如果 include 出现于调用文件中的一个函数里,则被调用的文件中所包含的所有代码将表现得如同它们是在该函数内部定义的一样。所以它将遵循该函数的变量范围。
当一个文件被包括时,语法解析器在目标文件的开头脱离 PHP 模式并进入 HTML 模式,到文件结尾处恢复。由于此原因,目标文件中应被当作 PHP 代码执行的任何代码都必须被包括在有效的 PHP 起始和结束标记之中.
4> 因为 include() 是一个特殊的语言结构,其参数不需要括号。在比较其返回值时要注意。
<?php // won't work, evaluated as include(('vars.php') == 'OK'), i.e. include('') if (include('vars.php') == 'OK') { echo 'OK'; } // works if ((include 'vars.php') == 'OK') { echo 'OK'; } ?>
个人理解: 1> 在不使用 ./ ../ 时会寻找程序设置的include_path, 如果使用了 ./ ../ 则程序中的include_path将失效。
2> 在包含文件是,如果想要“找不到包含文件时给出合理的提示信息”,就建议使用 include. 如下代码:
if(!@include_once('./config/config_global.php')) { exit('config_global.php is missing'); }如果文件 config_global.php,找不到则会给出提示:config_global.php is missing . 如果上面使用 require_once,则在找不到文件时直接会有一个致命的错误,将不会继续执行下面的代码,友好提示也就没有了。
正则表达式边界符妙用
<?php $html = "hello<script>alert(123)</script>world"; $str = preg_replace( array( "/<script[^>]*?>.*?</script>/si" ), array( "" ), $html ); var_dump($str); ?>在这样的代码中会出现一个错误:
Warning: preg_replace() [function.preg-replace]: Unknown modifier 'c' in D:\WAMP\www\test\html.php on line 11原因是上面的正则表达式出现异常了,把下面的代码替换就会正常执行
"/<script[^>]*?>.*?</script>/si"
"'<script[^>]*?>.*?</script>'si"
因为在上面代码中的正则表达式里有</script>中有 / ,所以程序会认为这个正则表达式已经结束,其实后面还有代码,所以为出错。
总之,其边界符虽然可以比较随意的使用,没有固定的限制,但是还是得多多注意,有时候随意不得。
安装php扩展:Xdebug
之前一直没有使用xdebug,程序依然跑的飞快。但是对于底层怎么解析、处理写的这些php程序呢?不知道。xdebug或许可以对你有帮助。
xdebug 是 php的一个扩展库,需要专门安装才可以使用。以下介绍windows平台的安装过程。
1、下载xdebug扩展
打开 http://xdebug.org/download.php 。打开之后发现版本很多很多,但是不能随意使用,需要根据自己的php与操作系统等等环境决定。
再打开这个页面:http://xdebug.org/wizard.php 里面全部是英文,但不要畏惧,还是比较易懂的。大概意思就是:把你的phpinfo信息粘贴到那个文本框中,然后点击下面的 “Analyse my phpinfo() output” 这个按钮,然后它就会根据你的开发环境信息建议你安装什么版本了。
注意:
a. 不能粘贴通过浏览器打印phpinfo()信息后,查看到的html源码。看到打印出的信息之后直接复制即可。
b. 点击“Analyse my phpinfo() output”按钮之后,在生成的建议信息中注意下面几项:
Xdebug installed: 2.0.5
Windows: yes - Compiler: MS VC6 - Architecture: x86
PHP Version: 5.2.5
如果 xdebug 项为 No , 说明还没有安装,如果后面接着是 Installed 说明已经安装过了,不需要再安装。
还有关键性的就是 windows 项与 php version 项。VC6, 要根据这个参数来找对应的版本。
然后再回到 download 页面寻找对应的扩展包。根据上面的信息我找到了一个 “PHP 5.2 VC6 TS (32 bit) (MD5: 2fda6a9d67eb1b4d09a6dc6b23f09ab0)”。有人说,如果php版本是5.2及以下的是需要带“_TS”的xdebug版本,本人没有测试过,也不知道这个“_TS”是什么意思。
2、把下载到的扩展包放到 php 的扩展库目录下,比如我的是 D:\wamp\php\ext\
3、找到php运行时加载的 php.ini 文件,然后在最低端添加如下的配置项:
;载入Xdebug,根据上一步的目录决定 zend_extension_ts="D:\wamp\php\ext\php_xdebug-2.0.5-5.2.dll" ;xdebug配置 [Xdebug] ;开启自动跟踪 xdebug.auto_trace = On ;开启异常跟踪 xdebug.show_exception_trace = On ;开启远程调试自动启动 xdebug.remote_autostart = On ;开启远程调试 xdebug.remote_enable = On ;收集变量 xdebug.collect_vars = On ;收集返回值 xdebug.collect_return = On ;收集参数 xdebug.collect_params = On
如果php版本是5.2及以下版本需要是 zend_extension_ts 这个配置选项,如果是 5.3 及以上版本需要是 zend_extension。依然不知道为什么?不过可以肯定5.2.5版本确实是如此,更低的版本与更高的版本没有测试过,“_ts” 是何物?
4、验证是否安装成功。(需要重新启动apache,或者是php-fpm)
依然根据phpinfo() 输出信息查看。
接着根据运行一段代码验证,如果运行输出结果说明安装成功,如果出现异常说明安装失败。
<?php $a = "new string"; $b = &$a; $a = null; xdebug_debug_zval( 'a' ); xdebug_debug_zval( 'b' ); ?>
【转载】 Apache 中 KeepAlive 配置的合理使用
在 Apache 服务器中,KeepAlive 是一个布尔值,On 代表打开,Off 代表关闭,这个指令在其他众多的 HTTPD 服务器中都是存在的。
KeepAlive 配置指令决定当处理完用户发起的 HTTP 请求后是否立即关闭 TCP 连接,如果 KeepAlive 设置为On,那么用户完成一次访问后,不会立即断开连接,如果还有请求,那么会继续在这一次 TCP 连接中完成,而不用重复建立新的 TCP 连接和关闭TCP 连接,可以提高用户访问速度。
那么我们考虑3种情况:1。用户浏览一个网页时,除了网页本身外,还引用了多个 javascript 文件,多个 css 文件,多个图片文件,并且这些文件都在同一个 HTTP 服务器上。
2。用户浏览一个网页时,除了网页本身外,还引用一个 javascript 文件,一个图片文件。
3。用户浏览的是一个动态网页,由程序即时生成内容,并且不引用其他内容。
对于上面3中情况,我认为:1 最适合打开 KeepAlive ,2 随意,3 最适合关闭 KeepAlive
下面我来分析一下原因。
在 Apache 中,打开和关闭 KeepAlive 功能,服务器端会有什么异同呢?先看看理论分析。
打开 KeepAlive 后,意味着每次用户完成全部访问后,都要保持一定时间后才关闭会关闭 TCP 连接,那么在关闭连接之前,必然会有一个Apache 进程对应于该用户而不能处理其他用户,假设 KeepAlive 的超时时间为 10 秒种,服务器每秒处理 50个独立用户访问,那么系统中 Apache 的总进程数就是 10 * 50 = 500 个,如果一个进程占用 4M 内存,那么总共会消耗 2G内存,所以可以看出,在这种配置中,相当消耗内存,但好处是系统只处理了 50次 TCP 的握手和关闭操作。
如果关闭 KeepAlive,如果还是每秒50个用户访问,如果用户每次连续的请求数为3个,那么 Apache 的总进程数就是 50 * 3= 150 个,如果还是每个进程占用 4M 内存,那么总的内存消耗为 600M,这种配置能节省大量内存,但是,系统处理了 150 次 TCP的握手和关闭的操作,因此又会多消耗一些 CPU 资源。
在看看实践的观察。我在一组大量处理动态网页内容的服务器中,起初打开 KeepAlive功能,经常观察到用户访问量大时Apache进程数也非常多,系统频繁使用交换内存,系统不稳定,有时负载会出现较大波动。关闭了 KeepAlive功能后,看到明显的变化是: Apache 的进程数减少了,空闲内存增加了,用于文件系统Cache的内存也增加了,CPU的开销增加了,但是服务更稳定了,系统负载也比较稳定,很少有负载大范围波动的情况,负载有一定程度的降低;变化不明显的是:访问量较少的时候,系统平均负载没有明显变化。
总结一下:在内存非常充足的服务器上,不管是否关闭 KeepAlive 功能,服务器性能不会有明显变化;
如果服务器内存较少,或者服务器有非常大量的文件系统访问时,或者主要处理动态网页服务,关闭 KeepAlive 后可以节省很多内存,而节省出来的内存用于文件系统Cache,可以提高文件系统访问的性能,并且系统会更加稳定。
补充1:关于是否应该关闭 KeepAlive 选项,我觉得可以基于下面的一个公式来判断。在理想的网络连接状况下,系统的 Apache 进程数和内存使用可以用如下公式表达:HttpdProcessNumber = KeepAliveTimeout * TotalRequestPerSecond / Average(KeepAliveRequests)
HttpdUsedMemory = HttpdProcessNumber * MemoryPerHttpdProcess
换成中文:
总Apache进程数 = KeepAliveTimeout * 每秒种HTTP请求数 / 平均KeepAlive请求
Apache占用内存 = 总Apache进程数 * 平均每进程占用内存数
需要特别说明的是:
[平均KeepAlive请求] 数,是指每个用户连接上服务器后,持续发出的 HTTP 请求数。当 KeepAliveTimeout 等 0或者 KeepAlive 关闭时,KeepAliveTimeout 不参与乘的运算从上面的公式看,如果 [每秒用户请求]多,[KeepAliveTimeout] 的值大,[平均KeepAlive请求] 的值小,都会造成 [Apache进程数] 多和 [内存]多,但是当 [平均KeepAlive请求] 的值越大时,[Apache进程数] 和 [内存] 都是趋向于减少的。
基于上面的公式,我们就可以推算出当 平均KeepAlive请求 <= KeepAliveTimeout 时,关闭 KeepAlive 选项是划算的,否则就可以考虑打开。
补充2: KeepAlive 该参数控制Apache是否允许在一个连接中有多个请求,默认打开。但对于大多数论坛类型站点来说,通常设置为off以关闭该支持。
补充3: 如果服务器前跑有应用squid服务,或者其它七层设备,KeepAlive On 设定要开启持续长连接
实际在 前端有 squid 的情况下, KeepAlive 很关键。记得 On!【转载】Js获取浏览器width/height
网页可见区域宽:document.body.clientWidth
网页可见区域高:document.body.clientHeight
网页可见区域宽:document.body.offsetWidth (包括边线的宽)
网页可见区域高:document.body.offsetHeight (包括边线的宽)
网页正文全文宽:document.body.scrollWidth
网页正文全文高:document.body.scrollHeight
网页被卷去的高:document.body.scrollTop
网页被卷去的左:document.body.scrollLeft
网页正文部分上:window.screenTop
网页正文部分左:window.screenLeft
屏幕分辨率的高:window.screen.height
屏幕分辨率的宽:window.screen.width
屏幕可用工作区高度:window.screen.availHeight
屏幕可用工作区宽度:window.screen.availWidth
HTML精确定位:scrollLeft,scrollWidth,clientWidth,offsetWidth
scrollHeight: 获取对象的滚动高度。
scrollLeft:设置或获取位于对象左边界和窗口中目前可见内容的最左端之间的距离
scrollTop:设置或获取位于对象最顶端和窗口中可见内容的最顶端之间的距离
scrollWidth:获取对象的滚动宽度
offsetHeight:获取对象相对于版面或由父坐标 offsetParent 属性指定的父坐标的高度
offsetLeft:获取对象相对于版面或由 offsetParent 属性指定的父坐标的计算左侧位置
offsetTop:获取对象相对于版面或由 offsetTop 属性指定的父坐标的计算顶端位置
event.clientX 相对文档的水平座标
event.clientY 相对文档的垂直座标
event.offsetX 相对容器的水平坐标
event.offsetY 相对容器的垂直坐标
document.documentElement.scrollTop 垂直方向滚动的值
event.clientX+document.documentElement.scrollTop 相对文档的水平座标+垂直方向滚动的量
IE,FireFox 差异如下:
IE6.0、FF1.06+:
clientWidth = width + padding
clientHeight = height + padding
offsetWidth = width + padding + border
offsetHeight = height + padding + border
IE5.0/5.5:
clientWidth = width - border
clientHeight = height - border
offsetWidth = width
offsetHeight = height
(需要提一下:CSS中的margin属性,与clientWidth、offsetWidth、clientHeight、offsetHeight均无关)
网页可见区域宽: document.body.clientWidth
网页可见区域高: document.body.clientHeight
网页可见区域宽: document.body.offsetWidth (包括边线的宽)
网页可见区域高: document.body.offsetHeight (包括边线的高)
网页正文全文宽: document.body.scrollWidth
网页正文全文高: document.body.scrollHeight
网页被卷去的高: document.body.scrollTop
网页被卷去的左: document.body.scrollLeft
网页正文部分上: window.screenTop
网页正文部分左: window.screenLeft
屏幕分辨率的高: window.screen.height
屏幕分辨率的宽: window.screen.width
屏幕可用工作区高度: window.screen.availHeight
屏幕可用工作区宽度: window.screen.availWidth
-------------------
技术要点
本节代码主要使用了Document对象关于窗口的一些属性,这些属性的主要功能和用法如下。
要得到窗口的尺寸,对于不同的浏览器,需要使用不同的属性和方法:若要检测窗口的真实尺寸,在Netscape下需要使用Window的属性;在 IE下需要深入Document内部对body进行检测;在DOM环境下,若要得到窗口的尺寸,需要注意根元素的尺寸,而不是元素。
Window对象的innerWidth属性包含当前窗口的内部宽度。Window对象的innerHeight属性包含当前窗口的内部高度。
Document对象的body属性对应HTML文档的标签。Document对象的documentElement属性则表示HTML文档的根节点。
document.body.clientHeight表示HTML文档所在窗口的当前高度。document.body. clientWidth表示HTML文档所在窗口的当前宽度。
关于获取各种浏览器可见窗口大小的一点点研究。
在我本地测试当中:在IE、FireFox、Opera下都可以使用
document.body.clientWidth
document.body.clientHeight即可获得,很简单,很方便。
而在公司项目当中:Opera仍然使用
document.body.clientWidth
document.body.clientHeight
可是IE和FireFox则使用
document.documentElement.clientWidth
document.documentElement.clientHeight
原来是W3C的标准在作怪啊http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
如果在页面中添加这行标记的话
在IE中:document.body.clientWidth ==> BODY对象宽度
document.body.clientHeight ==> BODY对象高度
document.documentElement.clientWidth ==> 可见区域宽度
document.documentElement.clientHeight ==> 可见区域高度
在FireFox中:document.body.clientWidth ==> BODY对象宽度
document.body.clientHeight ==> BODY对象高度
document.documentElement.clientWidth ==> 可见区域宽度
document.documentElement.clientHeight ==> 可见区域高度?
在Opera中: document.body.clientWidth ==> 可见区域宽度
document.body.clientHeight ==> 可见区域高度
document.documentElement.clientWidth ==> 页面对象宽度(即BODY对象宽度加上Margin宽)document.documentElement.clientHeight ==> 页面对象高度(即BODY对象高度加上Margin高)
而如果没有定义W3C的标准,
则IE为:document.documentElement.clientWidth ==> 0
document.documentElement.clientHeight ==> 0
FireFox为:document.documentElement.clientWidth ==> 页面对象宽度(即BODY对象宽度加上Margin宽)
document.documentElement.clientHeight ==> 页面对象高度(即BODY对象高度加上Margin高)
Opera为:document.documentElement.clientWidth ==> 页面对象宽度(即BODY对象宽度加上Margin宽)
document.documentElement.clientHeight ==> 页面对象高度(即BODY对象高度加上Margin高)
真是一件麻烦事情,其实就开发来看,宁可少一些对象和方法,不使用最新的标准要方便许多啊。
转载自:http://blog.csdn.net/zjlovety/article/details/6641644
如有任何差错请回帖指出哦,方便修正。
写Shell程序,小试牛刀
#!/bin/sh # # 各台web机器把记录的Cache Key排重后发送给cron机器 # # 使用示例 # 说明:每天凌晨执行,如果没有加时间参数,默认值为前一天 # ./rsyncCacheKeys_step1.sh [20130529] # 用法:将此命令加入到crontab, 保证每天只调用一次, 调用时间为每天 00:20 # 20 0 * * * /path/to/rsyncCacheKeys_step1.sh >/path/to/rsyncCacheKeys_step1.log # 配置信息 SSH_REMOTE_ADDR="10.6.207.220" ; SSH_REMOTE_USERNAME="kevon" ; LOCAL_LOG_PATH="/data/web/manyou/logs/cache" ; REMOTE_LOG_PATH="." ; SSH_IDENTITY_FILE="./sshkey/identity" ; #表示在该脚本同目录下,在真正执行命令时,此文件必须是绝对路径 # 用当前IP作为远程文件名的前缀 ##### IP地址需要在真实环境中进行调整 ##### # MY_IPADDRS=`/sbin/ifconfig |grep "inet addr"|awk '{print $2}'|awk -F: '{print $2}'|grep -v "127.0.0.1"|grep "192.168."` ; MY_IPADDRS=`/sbin/ifconfig |grep "inet addr"|awk '{print $2}'|awk -F: '{print $2}'|grep -v "127.0.0.1"` ; MY_IPADDR=`echo $MY_IPADDRS|awk '{print $1}'` ; LOG_PART=`echo $MY_IPADDR|awk -F. '{print $4}'` ; # 计算日期 # eg. DATE="20081229" DATE=`date +%Y%m%d -d "yesterday"` ; if [ x"$1" != x"" ] ; then DLEN=`expr length $1` ; if [ $DLEN -eq 8 ] ; then true ; DATE=$1 ; echo "You want process $DATE log. OK" ; else echo "Date format invalid: $1 . Should be like 20081230" ; exit 1 ; fi fi # 当前目录 CUR_DIR=`dirname $0` ; CUR_DIR=`readlink -f $CUR_DIR` ; # 自动生成 identity文件 # eg. IdKey /data/web/.../sshkey/id_rsa.pub echo "IdKey $CUR_DIR/sshkey/id_rsa" > $CUR_DIR/sshkey/identity 2>&1 # SSH_IDENTITY_FILE 转换为绝对地址 FIRSTCHAR=`echo $SSH_IDENTITY_FILE | cut -c 1` ; if [ "${FIRSTCHAR}" != "/" ] ; then SSH_IDENTITY_FILE=$CUR_DIR/$SSH_IDENTITY_FILE ; SSH_IDENTITY_FILE=`readlink -f $SSH_IDENTITY_FILE` ; # echo "Rewritten to: $SSH_IDENTITY_FILE" ; fi # 传送的文件类型 KEY_TYPES=(update select) ; ##################### # 检查并合并文件 # KEY_FILES=("$LOCAL_LOG_PATH/update_$DATE.log" "$LOCAL_LOG_PATH/select_$DATE.log") ; # UNIQ_KEY_FILES=("$LOCAL_LOG_PATH/update_uniq_$DATE.log" "$LOCAL_LOG_PATH/select_uniq_$DATE.log") ; ##################### for TYPE in ${KEY_TYPES[@]} do KEY_FILE="$LOCAL_LOG_PATH/${TYPE}_$DATE.log" ; UNIQ_KEY_FILE="$LOCAL_LOG_PATH/${TYPE}_uniq_$DATE.log" ; REMOTE_KEY_FILE="$REMOTE_LOG_PATH/${TYPE}_${DATE}_${LOG_PART}.log"; if [ -e $KEY_FILE ] ; then cat $KEY_FILE | sort | uniq > $UNIQ_KEY_FILE ; # 合并后删除原文件 # rm -f $KEY_FILE # 创建目录省去 # ssh -o StrictHostKeyChecking=no -i $SSH_IDENTITY_FILE $SSH_REMOTE_USERNAME@$SSH_REMOTE_ADDR mkdir -pv $REMOTE_LOG_PATH/ 2>&1 # 开始传送 scp -o StrictHostKeyChecking=no -i $SSH_IDENTITY_FILE $UNIQ_KEY_FILE $SSH_REMOTE_USERNAME@$SSH_REMOTE_ADDR:$REMOTE_KEY_FILE 2>&1 # 验证是否有错误 RCODE=$? ; if [ x"$RCODE" == x"0" ] ; then # 传输后删除 SELECT 操作的文件 if [ "select" == $TYPE] ; then # rm -f $UNIQ_KEY_FILE ; fi echo "Ok scp. " ; else echo "Error scp: $RCODE ." ; fi else echo "Key File not exist: $KEY_FILE ." ; fi done
IE中setAttribute("onclick","")与$("#abc").attr("onclick","")不起作用
$("#favorite").attr("onclick","activity.favorite("+aid+",'cancel')");使用这样的写法在FF与chrome下正常执行,却在IE8下不起作用,为达到兼容各种浏览器的效果,看如下代码:
$("#favorite").unbind("click"); //解除之前绑定的事件,这行代码可以根据情况取舍 $("#favorite").click(function(){activity.favorite(aid,'cancel')});这里只是一种思路,在其他情况下执行类似的操作遇到问题,不妨试试这种方法。
如何得到这种格式"频繁刷" ?
<?php mb_internal_encoding('utf-8'); // 这里的utf-8是你网站编码,也就是当前文件的编码 mb_http_output('HTML-ENTITIES'); ob_start('mb_output_handler'); echo '撒旦法撒旦法阿斯顿啊'; ?>2. 打开浏览器访问此php文件
3. 打开所谓的“抓包工具”(这里用的ie8,选择的工具是 httpwatch professional,也可以用firfox 的firbug), 然后就会在这个工具的控制台看到如下图的内容:
HTTP/1.1 200 OK Date: Mon, 27 Feb 2012 15:14:51 GMT Server: Apache/2.2.6 (Win32) PHP/5.2.5 X-Powered-By: PHP/5.2.5 Content-Length: 81 Keep-Alive: timeout=5, max=100 Connection: Keep-Alive Content-Type: text/html; charset=HTML-ENTITIES 撒旦法撒旦法阿斯顿啊最下面一行就是上面的汉字,可以复制的。。
ps : 这个有什么作用呢?这样的编码在任意编码环境下页面都能正常显示。还可以让别人在看你代码的时候有点晕。
linux系统上创建软链接
linux中的软链接,在windows中有个样板,那就是快捷方式。这个功能很好,很好。
用法: ln -s 真实存在的文件或目录 要创建的快捷方式
比如,有一个/usr/local/rzsz/rz (上传文件命令)文件,想放到 /home/root目录下,命令如下:
ln -s /usr/local/rzsz/rz /root/bin/rz
ln 命令的用法很多,这里的 -s 是指创建软链接,第一个参数是真实存在的文件或目录,第二个参数才是要创建的链接名称