PPJ回忆录(Python,PHP,Javascript)

by emptyhua@gmail.com

做为一个半瓶醋的各种Language coder,我感到压力很大,经常在几种语言之间倒来切去,最终决定整理一个帮助对比回忆的文档。

这不是手册也不是入门指南,不能让你理解或入门任何一门语言!!

代码测试环境

Ubuntu 10.10 i386
Python 2.6.6
PHP 5.3.3
Firefox 3.6.13
        
更新日志

参考链接和书目

简介

Python PHP Javascript
起源 Python的创始人为Guido van Rossum。1989年圣诞节期间,在阿姆斯特丹,Guido为了打发圣诞节的无趣,决心开发一个新的脚本解释程序,做为 ABC 语言的一种继承。之所以选中 Python(大蟒蛇的意思)作为程序的名字,是因为他是一个Monty Python的飞行马戏团的爱好者。
了解更多
PHP,全称为PHP Hypertext Preprocessor,超文本预处理器。
PHP起源于1995年,由当时年仅17岁的Rasmus Lerdorf编写完成,是使用Perl技术为基础的服务器端脚本。主要的用途是跟踪收集浏览个人网站简历的信息,由于它主要的功能是表单的转换、信息收集工作,因此被Lerdorf命名为Personal Home Page Tools/Form Interpreter,简称PHP/FI。
了解更多
1995年,Javascript 1.0伴随着网景公司的Netscape Navigator 2.0而诞生。到现在它几乎是所有浏览器必须支持的语言。
了解更多
特点 Python是一门通用编程语言,可用于Web开发,GUI开发,网络编程,数据分析等各种应用。另外python语法简洁,类型方面没有歧义,更容易入门。 PHP在web开发领域几乎无人能敌,有人说它2小时可以入门。但是如果想真正理解它却并非易事。 一个只用JS验证过表单的Coder几乎无法理解JS程序员能写出像Gmail这种应用.JS做为一门注释里出现Fuck最多的语言,不仅是因为本身的古怪语法,也因为它有各种不同的解释引擎。

词法

Python PHP Javascript
续行符 \ 木有,直接换行 木有,直接换行
注释
#我是单行注释
"我也是单行注释"
"""
我是多行注释
使用未赋值的字符串做注释
"""
                
对于字符串型的注释 如果注释出现在文件开头,那么它将成为一个模块文档
如果出现在函数定义之后,成为一个函数文档
如果出现在class定义之后,成为一个类的说明文档
文档在运行时是可以访问的
>>> def foo():
...     '''
... i am foo
... void foo(void);
...     '''
...     pass
... 

>>> print foo.__doc__

i am foo
void foo(void);
	
                
C style: // /* */ C style: // /* */
空行
for i in xrange(100):
    pass
                
for($i = 0; $i < 100; $i++);
                
for(var i = 0; i < 100; i++);
                

类型

Python PHP Javascript
说明 一切皆对象
>>> (2.0).is_integer()
True
                
PHP中的基本类型和对象是孤立的 一切皆对象
>>> (1).toString()
"1"
                
强类型?
>>> '12' == 12
False
>>> "test" + 1
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: cannot concatenate 'str' and 'int' objects
                
不是
php > var_dump('12' == 12);
bool(true)
php > var_dump('12' === 12);
bool(false)
                
不是
>>> "12" == 12
true
>>> "12" === 12
false
                
对于PHP和JS使用"==="真等于符是一种好习惯

整型

Python PHP Javascript
说明 python的整型分"标准整型"和"长整型" 在JS中所有数字都是由浮点型表示
范围 标准整型:
跟宿主系统有关系,在32位机器上范围:-2^31 ~ 2^31-1

长整型:
长整型的长度只跟机器所支持的虚拟内存大小有关
#长整型直接量需要在后面加字符"L"
long1 = -0xFFFFFL
long2 = 312432L
                
2.4版本以后标准整型溢出之后会自动转换为长整
跟宿主系统有关系,在32位机器上范围:-2^31 ~ 2^31-1
整型溢出后会自动转换为浮点(float)
-2^53 -> 2^53
特殊常量
#import sys
#最大的标准整型
print sys.maxint
                
PHP_INT_MAX //常量,表示整型最大值 Infinity //无穷大
NaN //非数字值
Number.MAX_VALUE //可表示最大数字
Number.MIN_VALUE //可表示最小数字
Number.POSITIVE_INFINITY //正无穷大
Number.NEGATIVE_INFINITY //负无穷大
16进制直接量 0xff or 0XFF 0xff or 0XFF 0xff or 0XFF
8进制直接量 0377 == 255//0开头 0377 == 255//0开头 ECMAScript标准不支持8进制直接量,但是浏览器js引擎却支持了。
0377 == 255 //0开头
                

浮点型

Python PHP Javascript
范围 范围约为-10^308.25 ~ 10^308.25 跟宿主系统有关,通常范围约为-10^308.25 ~ 10^308.25 范围约为-10^308.25 ~ 10^308.25

布尔型

Python PHP Javascript
表示 True False
True和False都不是关键字,你甚至可以颠倒是非
True, False = False, True
                    
true false true false
自动转换 下面的值被认为是false:
  • None
  • False
  • 数字0,0L,0.0,0j
  • 空序列 '',(),[]
  • 空hash {}
  • 对于一个对象,如果定义了__nonzero__或__len__方法,
    如果方法返回0或者False,这对象被认为是false
下面的值被认为是false:
  • false
  • 整型 0
  • 浮点 0.0
  • 字符串""和"0"
  • array() 空数组
  • new StdClass() 空对象
  • null
  • 没有任何标记的SimpleXML对象
下面的值被认为是false:
  • false
  • undefined
  • null
  • 空字符串""
  • NaN
  • 无穷和负无穷
  • 数字0 和 0.0

字符串

Python PHP Javascript
双引号 支持 支持 支持
单引号 支持 支持
对于PHP,在单引号字符串中的变量 和特殊含义的字符将 不会 被替换
支持
here document python中使用三个单引号或者三个双引号
print '''
test
test
'''
print """
test
test
"""
                
Heredoc也支持转义和变量替换
$a = 'var 1';
$b = 'var b';
$str = >>>EOD
Example of string
spanning multiple lines
using heredoc syntax.
a = ${a}
b = ${b}
EOD;
                
PHP中还有一种Nowdoc的方式,了解更多
不支持
转义字符 以r或R打头的字符串不会做以下转义,这种字符串称为原始字符串
>>> r'abc\"def\t'
'abc\\"def\\t'
                
\0  C里的'\0'
\a  响铃
\b  退格
\t  
\n
\v  纵向制表
\f  换页
\r
\e  ESC
\"
\'
\\
\XX 八进制字符
\xXX 十六进制字符
\ 连字符
                
单引号和Nowdoc形式定义的字符串不会做以下转义
\n
\r
\t
\v
\f
\\
\$
\"
\XXX 八进制字符
\xXX 十六进制字符
                
\r
\"
\'
\\
\xXX 十六进制字符
\xXXXX 十六进制unicode字符
                
连接操作符
c = 'a' + 'b'
                
$c = 'a' . 'b';
                
var c = 'a' + 'b';
                
下标访问
>>> 'abc'[0]
'a'
                
php > $a = 'abc';
//推荐写法
php > echo $a[0];
a
php > echo $a{0};
a
                
>>> 'abc'.charAt(0);
"a"
//ECMAScript 5也有定义下标的语法,你可以用最新的firefox测试
>>> 'abc'[0]
"a"
                
取长度
>>> len("中文")
6
>>> len(u"中文")
2

                
echo strlen('中文');
//6
echo mb_strlen('中文', 'UTF-8');
//2
                
>>> '中文'.length
2
                
转换为数字
#默认会当作10进制处理
>>> int('012')
12
#指定做8进制解析
>>> int('012', 8)
10

                
php > echo '012' - 0;
12
php > echo (integer)'012';
12
php > echo intval('012');
12
php > echo intval('012', 8);
10
                
注意JS的陷阱
>>> '012' - 0
12
>>> parseInt('012')
10
//打印10, JS竟然替我们做了一个艰难的决定。。。
>>> parseInt('012', 10)
12
                
编码 python中有两种字符串类型str和unicode
str是一种字节串,可以理解为C语言里的char[]
str型的字符串的编码跟python脚本文件的编码一致

unicode是一种unicode编码字符串,跟文件编码无关
>>> cstr = '普通字符串'
>>> ustr = u'unicode字符串'
>>> len(cstr)
15
>>> len(ustr)
10
>>> cstr[0]
'\xe6'
>>> ustr[8]
u'\u7b26'
                
str和unicode转换
ustr = u'我是unicode字符串'
#编码成utf8编码的str型字符串
utfstr = ustr.encode('utf-8')
#编码成gb2312编码的str型字符串
gbstr = ustr.encode('gb2312')
#将gb2312编码的str型字符串解码成unicode型的ustr2
ustr2 = gbstr.decode('gb2312')
                
str和unicode的强制转换
#str和unicode型字符串做连接操作会将str强制转换成unicode
>>> u'a' + 'b'
u'ab'
#相当于执行了u'a' + 'b'.decode(sys.getdefaultencoding())
#sys.getdefaultencoding()用于获取默认编码
#如果被格式化的参数中有unicode串,则其他参数也要强制转换到unicode
>>> '%s%s' % (u'a', 'b')
u'ab'
>>> '%s%s' % (u'a', '中文')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode 
byte 0xe4 in position 0: ordinal not in range(128)
>>> sys.getdefaultencoding()
'ascii'
#出错原因在于'中文'.decode('ascii')
#通过ascii解码'中文'两个字是不可能的
                
了解更多
PHP中的string是一种字节串,编码跟PHP文件的编码一致
                
JS中的字符串是unicode字符串,跟文件编码无关。
alert('中文'.charCodeAt(0));
//不论utf8或gb2312编码的环境中都将打印20013
                
server端收到数据编码总是跟网页编码一致,这跟JS的字符串编码无关

索引数组&&关联数组

Python PHP Javascript
说明 Python有两种称为列表(list)和元组(tuple)的序列类型
用以实现索引数组,一种可变一种不可变,这里以列表为例。
Python还有一种字典(dict)类型,用于实现hash数组
PHP中不区分索引数组和Hash数组,即全是Hash
php > $a = array();
php > $a[0] = 'test';
php > $a[1] = 'test2';
php > $a['1'] = 'test3';
php > echo $a[1];
test3
php > echo $a['1'];
test3

                
JS跟PHP类似,没有真正的索引数组,全是Hash
>>> a = ['动','感','超','人'];
["动", "感", "超", "人"]
>>> b = {'0':'动','1':'感','2':'超','3':'人'};
Object { 0="动", 1="感", more...}
>>> a[2]
"超"
>>> b[2]
"超"
>>> a['2']
"超"
>>> b['2']
"超"
                
定义
#列表直接量
#列表也可以存储混合类型的数据
>>> a = [1,2,3,"4"]
>>> a
[1, 2, 3, '4']
#通过工厂函数初始化
>>> a = list((1,2,3,4,5))
>>> a
[1, 2, 3, 4, 5]

>>> len(a)
5
>>> a.append('addon')
>>> len(a)
6

#字典直接量
#字典的key可以是任意可hash的不可变类型
>>> b = {'k1':'i am k1',100:'i am 100'}
>>> b
{'k1': 'i am k1', 100: 'i am 100'}

#通过工厂初始化
>>> d = dict(a = 1, b = 2)
>>> d
{'a': 1, 'b': 2}

>>> a[100]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: list index out of range
>>> b['c']
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'c'
#访问不存在的索引,或者键值,python将会抛出异常
                
php > $a = array('k1'=>1,'k2'=>2,30=>3,40=>4);
php > echo count($a);
4
php > var_dump($a);
array(4) {
  ["k1"]=>
  int(1)
  ["k2"]=>
  int(2)
  [30]=>
  int(3)
  [40]=>
  int(4)
}
php > $a = array(0=>1,30=>3,40=>4);
//说明数组的长度并不是最大的索引值,foreach遍历更安全
php > echo count($a);
3
php > echo $a[100];
PHP Notice:  Undefined offset: 100 in php shell code on line 1
PHP Stack trace:
PHP   1. {main}() php shell code:0
//访问不存在的key只会有Notice产生,生产环境中一般会配置将Notice忽略

                
//直接量
>>> a = [1,2,3,4];
[1, 2, 3, 4]
//调用构造函数
>>> a = new Array();
[]
>>> a[99] = 'i am 100';
"i am 100"
>>> a.length
100
>>> a['k1'] = 'i am k1';
"i am k1"
>>> a.length
100
>>> delete a[99]
true
>>> a.length
100
//说明JS中数组的长度只跟赋值过的最大索引值有关
>>> a[0]
undefined
>>> a[100]
undefined
//所有未赋值的索引调用都将返回undefined
                
另:JS中所有可以转换为字符串的对象都可以做为Hash Key

变量

Python PHP Javascript
变量声明 变量不需要声明 变量不需要声明
function foo()
{
    var i; //变量声明
    i = 0;
    j = 0;//变量可以不声明,但是j将变成一个全局变量
}
                
判断变量是否定义
try:
    print xxxx
except NameError,ex:
    print 'xxxx is undefined'
                
php > var_dump(isset($xxxxx));
bool(false)
                
if (typeof xxxx != 'undefined')
                
赋值 理解赋值之前我们需要理解:
在这三种脚本语言中,变量名和变量本身是独立的,只能说变量名可以代表一个变量
Python中的赋值为赋引用
>>> L1 = ['list em']
>>> L2 = L1
>>> L2.append('add another')
>>> L1
['list em', 'add another']
>>> L2
['list em', 'add another']
                
L2 = L1并不会copy L1给L2,只是创建了L2到变量的引用

python中的赋值操作没有返回值
>>> a = (b = 'c')
  File "<stdin>", line 1
    a = (b = 'c')
           ^
SyntaxError: invalid syntax
                
由于PHP中普通类型和对象是独立的,就把对象的内容提到前面来了,所以有点复杂。。

PHP中的赋值比较复杂
普通赋值相当于变量复制(copy on write)
php > $a = array('i am a string');
php > $b = $a;
//创建了新变量$b并copy $a的值给它
php > $b[] = 'add another';
php > var_dump($a);
array(1) {
  [0]=>
  string(13) "i am a string"
}
php > var_dump($b);
array(2) {
  [0]=>
  string(13) "i am a string"
  [1]=>
  string(11) "add another"
}
                
对象赋值为赋引用
//Human的实例在对象编程部分,小穿越一下
$hm = new Human('han meimei');
$hm2 = $hm;
$hm2->name = 'li lei';
echo $hm->name;
                
输出:
li lei
                
创建变量"引用"的赋值可以认为创建了变量名的副本
php > $a = 'i am a';
php > $b = &$a;
//这个操作并不是变量赋值,而是创建变量a的引用
php > $b = 'i am b';
//$b和$a是等效的
php > echo $a;
i am b
                
JS中的赋值为赋引用
>>> a = [1,2,3]
[1, 2, 3]
>>> b = a
[1, 2, 3]
>>> b.push(4)
4
>>> a
[1, 2, 3, 4]
>>> b
[1, 2, 3, 4]
                
多重赋值(a = b = 1) 支持 支持 支持
多元赋值 python中利用了元组的特性
(x, y, z) = (1, 2, 3)
                
PHP中可利用list操作符
list($x, $y, $z) = array(1, 2, 3);
                
不支持
判断变量类型
>>> isinstance(3,int)
True
>>> isinstance('abc',str)
True
>>> isinstance([1,2],list)
True
                
php > var_dump(is_integer(3));
bool(true)
php > var_dump(is_string('abc'));
bool(true)
php > var_dump(is_array(array(1,2)));
bool(true)
                
了解更多
>>> typeof 3 == 'number'
true
>>> typeof 'abc' == 'string'
true
>>> typeof []
"object"
//对于数组来说 typeof 会返回 object,所以不能用此方法判断
//所以要采取下面这种方式
>>> Object.prototype.toString.call([1,2]) === '[object Array]'
true
                
获取变量类型
>>> type(3)
<type 'int'>
>>> type('abc')
<type 'str'>
>>> type([1,2])
<type 'list'>

                
php > echo gettype(3);
integer
php > echo gettype('abc');
string
php > echo gettype(array(1,2));
array
                
参考上面
变量格式化输出
>>> '%s is not %d' % ('a', 5)
'a is not 5'

                
php > printf("%s is not %d", 'a', 5); 
a is not 5
                
没有自带函数
调试打印 dir() str() var_dump() print_r() console.log() alert()

变量作用域

Python PHP Javascript
块级作用域? 木有 木有 木有
访问全局变量
a = 'global var'
#python中可以直接通过作用域搜索访问到全局变量
def foo1():
    print a
    #这里你并没有改变全局变量a,而是定义了一个局部变量a
    a = 'modify global var'
def foo2():
    #可以明确声明一个全局变量
    global a
    #修改全局变量
    a = 'modify global var'
    
                
$a = 'global var';
function foo()
{
//如果一个变量没有在函数内定义PHP并不会去搜索全局作用域
//如果需要访问全局变量,必须用global声明一个全局变量
    global $a;
    echo $a;
//通过全局变量数组访问
    echo $GLOBALS['a'];
}
                
$GLOBALS,$_POST,$_GET等这些变量被PHP称之为超全局变量,函数中不用声明就可以使用
var a = 'global var';
function foo()
{
//JS中通过作用域链搜索也可以直接访问全局变量
    alert(a);
//也可以直接修改全局变量,这是也为什么未声明变量的赋值会创建全局变量的原因
    a = 'modify global var';
}
                
打包(命名空间) python中使用目录结构来构建命名空间
$ tree ./
./
├── d
│   ├── hello.py
│   └── __init__.py
├── foo.py
└── test.py

1 directory, 4 files

$ cat foo.py 
#!/usr/bin/env python
name = 'my name is foo'

def print_name():
    print name

$ cat d/hello.py 
#!/usr/bin/env python

def echo():
    print 'i am hello.py'

$ cat test.py 
#!/usr/bin/env python
import foo
import d.hello as hello
print foo.name
foo.print_name()
hello.echo()


$ python test.py 
my name is foo
my name is foo
i am hello.py

                
PHP中使用namespace关键字构造命名空间
$ cat test.php 
<?php
namespace Hello;
function hi(){echo "i am hello\n";}
namespace Hello\World;
function hi(){echo "i am hello World\n";}
namespace Test;
\Hello\hi();
\Hello\World\hi();
use \Hello\World as HelloWorld;
HelloWorld\hi();
?>
$ php test.php 
i am hello
i am hello World
i am hello World

                
JS中通过闭包包装
var com = {foo:{}};

(function(ns)
{
    function privSayHi()
    {
        alert('hi'); 
    }

    ns.hi = function()
    {
        privSayHi();    
    };
})(com.foo);

function test()
{
    var hi = com.foo.hi;
    //相当于 import com.foo.hi as hi
    hi();
}

test();

                

条件和循环

Python PHP Javascript
条件表达式(三元操作符)
#python 2.5 or later
smaller = x if x < y else y
                
$smaller = $x < $y ? $x : $y;
                
var smaller = x < y ? x : y;
                
for(;;) 不支持 支持 支持
for in
for i in xrange(len(arr)):
    print arr[i]
#python 使用for in来遍历可迭代对象
                    
对于PHP使用foreach代替 for(;;)是一种推荐写法
//php没有for in 但是有foreach来遍历迭代
foreach($arr as $i => $v)
    echo $v;
                    
JS中也有for in循环,但是它的行为怪异,遍历顺序不定,甚至在不同的浏览器里也会有不同的表现
for (var x in [1,2,3])
    alert(x);
                    
跳出外层循环 python还没有语法支持
//通过在break后面跟一个数字,可以跳出指定层次的循环
foreach($a as $v)
    foreach($v as $vv)
        break 2;
                    
了解更多
JS则可以使用break加标签名的方式跳出
outerloop:
for (var i = 0; i < 100; ++i)
    for (var j = 0; j < 100; ++j)
        break outerloop;
                    

函数

Python PHP Javascript
传值?传引用? 在这之前请理解每种语言的变量赋值方式

传值或传引用只是看起来的表面现象,传值不一定慢
PHP的变量复制会采用copy on write策略:传值也仅仅传一个"指针"副本,不会真的拷贝一份,当你真的需要修改变量时才会执行copy动作。
Python总是"传引用"
gstr = 'global string'
gls = ['global list',1,2]

def m_str(v):
    #这里仅仅是是改变变量名副本v的引用关系,不影响gstr
    v = 'modify global string'

#可以理解为
# v = gstr  使变量名v指向gstr 
# v = 'modify global string'  改变变量名v的引用
# gstr不受影响

#Python的赋值方式使它的传引用现在看来像是传值

def m_hs(v):
    #变量名v未改变,改变的是v引用的list型
    变量的第一个元素的引用关系
    v[0] = 'modify global list'

#可以理解为
# v = gls  python的赋值为赋引用所以不会创建gls的副本
# v[0] = 'modify global list' 

m_str(gstr)
m_hs(gls)
print gstr
print gls
                
输出:
global string
['modify global list', (1, 2)]
                  
对于PHP,传递普通变量名为传值,传递引用型变量名为传引用
<?php
$a = array('i am global str');
function foo($b)
{
    $b[] = 'add another';
}

//理解为
//$b = $a
//普通赋值会创建新的变量$b,$a不受影响

function foo2(&$b)
{
    $b[] = 'add another';
}
//理解为
//$b = &$a;
//$b是一个引用型变量名,和变量名$a是等效的
//$b[] = 'add another'; 

foo($a);
var_dump($a);
foo2($a);
var_dump($a);
?>

                
输出:
array(1) {
  [0]=>
  string(15) "i am global str"
}
array(2) {
  [0]=>
  string(15) "i am global str"
  [1]=>
  string(11) "add another"
}
                
传递对象的变量名为"传引用"
//Human的例子见对象编程部分
$hm = new Human('han meimei');
function cname($hm)
{
    $hm->name = 'li lei';
}
cname($hm);
print $hm->name;
                
输出:
li lei
                
引用型变量名使得PHP的引用传参是在真的引用
<?php
$a = 'i am a';
function test(&$b)
{
    $b = 'i am b'; 
}
test($a);
var_dump($a);
?>
                
输出:
string(6) "i am b"
                
JS总是"传引用"的,
虽然权威指南说JS是部分类型传值,部分类型传引用,但是那样并不好理解
var sa = 'i am a string';
var aa = [1,2,3,4];
function foo(a)
{
    a = 'i am another string';
}

//可以理解为
//var a = sa;
//a = 'i am another string';
//a的赋值只是改变了变量名a的引用到'i am another string';
//sa不受影响

function foo2(b)
{
    b[0] = 'test'; 
}

//可以理解为
//var b = aa;  
//赋值为赋引用,b现在指向aa
//b[0] = 'test';

foo(sa);
foo2(aa);
console.log(sa);
console.log(aa);
                
输出:
i am a string
["test", 2, 3, 4]
                
允许重复定义? 允许,产生覆盖 不允许,产生Fatal error 允许,产生覆盖
嵌套定义? Python中嵌套定义的函数会变成外部函数作用域的闭包函数
>>> def foo():
...     def foo2():
...             print 'i am foo2'
...     foo2()
... 
>>> foo()
i am foo2
>>> foo2()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'foo2' is not defined

                
PHP中允许嵌套定义,但是定义的函数不能和全局函数重名
<?php
function test()
{
    function foo()
    {
        echo 'i am foo'; 
    }

    foo();
}

test();
?>
                
输出:
i am foo
                
<?php
function foo(){echo 'i am foo';}
function test()
{
    function foo()
    {
        echo 'i am foo too'; 
    }

    foo();
}

test();
?>
                
输出
PHP Fatal error:  Cannot redeclare foo() (pr
eviously declared in /tmp/test.php:2) in /tm
p/test.php on line 5
PHP Stack trace:
PHP   1. {main}() /tmp/test.php:0
PHP   2. test() /tmp/test.php:13
                
嵌套函数无法访问外部函数作用域
<?php
function test()
{
    $hi = 'i am test';

    function foo()
    {
        echo $hi;
    }

    foo();
}

test();
?>
                
输出:
PHP Notice:  Undefined variable: hi in /tmp/test.php on line 8
PHP Stack trace:
PHP   1. {main}() /tmp/test.php:0
PHP   2. test() /tmp/test.php:14
PHP   3. foo() /tmp/test.php:11
                
跟Python类似也会构成闭包函数,详见闭包部分
默认返回值 None
>>> def foo():
...     pass
... 
>>> print foo()
None

                    
null
php > function test(){}
php > var_dump(test());
NULL
php > var_dump(test() === null);
bool(true)
                    
undefined
>>> function test(){};
undefined
>>> test();
undefined
                    
传参
>>> def foo(a, b):
...     print a,b
... 
>>> foo('a', 'b')
a b
#python还有一种指定参数名的灵活调用方式
#可以不用按照顺序传参
>>> foo(b='b', a='a')
a b
#python会严格检查传参数目
>>> foo('a')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: foo() takes exactly 2 arg
uments (1 given)

                
php > function foo($a, $b){echo $a . $b;}
php > foo('a', 'b');
ab
//PHP也会检查参数个数,出错时产生Warning
php > foo('a');
PHP Warning:  Missing argument 2 for foo(), called
in php shell code on line 1 and defined in php she
ll code on line 1
PHP Stack trace:
PHP   1. {main}() php shell code:0
PHP   2. foo() php shell code:1
PHP Notice:  Undefined variable: b in php shell co
de on line 1
PHP Stack trace:
PHP   1. {main}() php shell code:0
PHP   2. foo() php shell code:1
a
                    
>>> function foo(a,b){console.log(a + b);}
>>> foo('a', 'b');
ab
//JS对参数个数完全不做检查
>>> foo('a');
aundefined
>>> foo('a', 'b', 'c');
ab
                    
默认参数
>>> def foo(a, b ='b'):
...     print a,b
... 
>>> foo('a')
a b

                    
php > function foo($a, $b='b'){echo $a . $b;}
php > foo('a');
ab
                    
没有语法支持
变长参数 Python有两种支持
非关键字变参:
>>> def foo(a, b, *m):
...     print a,b,''.join(m)
... 
>>> foo('a','b','c','d')
a b cd
                    
关键字传参的变参
>>> def foo(a, b, **m):
...     for k in m.keys():
...             print k,m[k]
... 
>>> foo('a','b',c='c',d='d')
c c
d d
                    
来自PHP manual的范例
<?php
function foo()
{
    $numargs = func_num_args();
    echo "Number of arguments: $numargs<br />\n";
    if ($numargs >= 2) {
        echo "Second argument is: " . func_get_arg(1) . "<br />\n";
    }
    $arg_list = func_get_args();
    for ($i = 0; $i < $numargs; $i++) {
        echo "Argument $i is: " . $arg_list[$i] . "<br />\n";
    }
}

foo(1, 2, 3);
?>
                    
输出:
Number of arguments: 3<br />
Second argument is: 2<br />
Argument 0 is: 1<br />
Argument 1 is: 2<br />
Argument 2 is: 3<br />
                
>>> function foo(){for(var i = 0;i < arguments.length;i++) console.log(arguments[i]);}
>>> foo('a','b','c');
a
b
c
                    
前向引用 Python中的函数在定义之前无法使用
foo()
def foo():
    print 'i am foo'
                
输出
Traceback (most recent call last):
  File "test.py", line 2, in 
    foo()
NameError: name 'foo' is not defined
                
可以
<?php
foo();
function foo()
{
    echo 'i am foo';
}
?>
                
输出:
i am foo
                
可以
foo();
function foo() 
{
   console.log('i am foo');
} 
                
输出:
i am foo
                
动态调用 Python中函数是可以引用的
>>> def foo():
...     print 'i am foo'
... 
>>> a = [1,2,foo]
>>> a[2]()
i am foo

                    
PHP中通过function foo();形式定义的全局函数是不可以赋值给变量的
但是我们依然有两种方式可以动态调用
php > function foo($a){echo 'i am ' . $a;}
php > call_user_func('foo', 'test');
i am test
php > $a = 'foo';
php > $a('test');
i am test
                    
JS中的函数也是可以直接引用的
>>> function foo(){console.log('i am foo');}
>>> window['foo']();
i am foo
>>> a = foo;
foo()
>>> a();
i am foo
                    
闭包
>>> def counter():
...     c = [0]
...     def add():
...             c[0] += 1
...             return c[0]
...     return add
... 
>>> c = counter()
>>> c()
1
>>> c()
2
>>> c()
3
                    
PHP从5.3.0开始支持闭包
匿名函数如果要访问外部函数作用域的变量必须通过use声明
<?php
function counter()
{
    $c = 0;
    return function() use (&$c)
    {
        return ++$c; 
    };
}
$c = counter();
var_dump($c());
var_dump($c());
var_dump($c());
?>
                    
输出:
int(1)
int(2)
int(3)
                    
实际编码中使用闭包最频繁的莫过于JS
function counter()
{
    var c = 0;
    return function()
    {
        return ++c;
    };
}
var c = counter();
console.log(c());
console.log(c());
console.log(c());
                    
输出:
1
2
3
                    

对象编程

Python PHP Javascript
说明 仅以PHP5以后的对象编程为例 JS的对象编程恐怕是最无厘头的,拿出来单独写一个文档都够了,仅通过下面的示例无法了解原理
定义
class Human(object):
    def __init__(self, name):
        self.name = name 
    def say(self, msg):
        print '%s:%s' % (self.name, msg)

hm = Human('li lei')
hm.say('hi han meimei~')
                    
输出:
li lei:hi han meimei~
                    
<?php
class Human
{
    function __construct($name)
    {
        $this->name = $name; 
    }

    function say($msg)
    {
        printf('%s:%s', $this->name, $msg); 
    }
}

$hm = new Human('li lei');
$hm->say('hi han meimei~');
?>

                    
输出:
li lei:hi han meimei~
                
function Human(name)
{
    this.name = name; 
}

Human.prototype = {
    say:function(msg) 
    {
        console.log(this.name + ':' + msg);   
    }
};

var hm = new Human('li lei');
hm.say('hi han meimei~');
                
输出:
li lei:hi han meimei~
                
实例类型判断
hm = Girl('han meimei')
print isinstance(hm, Girl)
print isinstance(hm, Human)
                
输出:
True
True
                
$hm = new Girl('han meimei'); 
var_dump(is_a($hm, 'Girl'));
var_dump(is_a($hm, 'Human'));
                
输出:
bool(true)
bool(true)
                
var hm = new Girl('han meimei');
console.log(hm instanceof Girl);
console.log(hm instanceof Human);
                
输出:
true
true
                
访问控制 (private,public) 默认情况下对象的属性和方法都是可见的,可以通过在名字前加'__'双下划线使其变成私有
class Human(object):
    def __init__(self, name):
        self.__name = name 
    def say(self, msg):
        print "%s:%s" % (self.__name, msg)
                
PHP中可以通过private和public关键字修饰
class Human
{
    private $name = '';
    function __construct($name)
    {
        $this->name = $name; 
    }

    function say($msg)
    {
        echo sprintf('%s:%s', $this->name, $msg); 
    }
}
                
对于JS,闭包再一次帮了它
function Human(name)
{
    this.name = function(v) 
    {
        if (typeof v == 'string') name = v; 
        return name;
    };
}

Human.prototype = {
    say:function(msg) 
    {
        console.log(this.name() + ':' + msg);   
    }
};
                
访问控制(protected) 不支持 使用protected关键字 不支持
静态成员 python中使用staticmethod函数修饰符
class Human(object):
    def __init__(self, name):
        self.name = name 
    def say(self, msg):
        print "%s:%s" % (self.name, msg)
    @staticmethod
    def get_name(hm):
       return hm.name 

hm = Human('li lei')
print Human.get_name(hm)
                
class Human
{
    function __construct($name)
    {
        $this->name = $name; 
    }

    function say($msg)
    {
        echo sprintf('%s:%s', $this->name, $msg); 
    }

    static function get_name($hm)
    {
        return $hm->name; 
    }
}

$hm = new Human('han meimei');
echo Human::get_name($hm);
                
JS的静态方法直接当作构造函数的属性就可以了
Human.get_name = function(hm)
{
    return hm.name;
};
                
继承
class Girl(Human):
    def __init__(self, name):
        super(Girl, self).__init__(name)
        self.sex = 'girl'

hm = Girl('han meimei')
hm.say('hi li lei~')
                    
输出:
han meimei:hi li lei~
                    
class Girl extends Human
{
    function __construct($name)
    {
        parent::__construct($name); 
        $this->sex = 'girl';
    }
}

$hm = new Human('han meimei');
$hm->say('hi li lei~');
                    
输出:
han meimei:hi li lei~
                    
对于原型继承,一句两句说不清
function Girl(name)
{
    Human.call(this, name); 
    this.sex = 'girl';
}

Girl.prototype = new Human();

var hm = new Girl('han meimei');
hm.say('hi li lei~');
                    
输出:
han meimei:hi li lei~
                    
多重继承 支持
class foo(P1, P2):
    pass
                
没有语法支持 没有语法支持
判断继承关系
print issubclass(Girl, Girl)
print issubclass(Girl, Human)
print issubclass(Girl, object)
                
输出:
True
True
True
                
//PHP中没有一个所有类的根类,所以这里再多定义一层
//PHP通过类的实例来判断继承关系
class YoungGirl extends Girl{}
$hm = new YoungGirl('han meimei');
var_dump(is_subclass_of($hm, 'YoungGirl'));
var_dump(is_subclass_of($hm, 'Girl'));
var_dump(is_subclass_of($hm, 'Human'));
                
输出:
bool(false)
bool(true)
bool(true)
                
//仅适用于例子中的继承方式
console.log(Girl.prototype instanceof Girl);
console.log(Girl.prototype instanceof Human);
console.log(Girl.prototype instanceof Object);
                
输出:
false
true
true
                
接口 没有,靠自觉
interface fooInterface
{
    function sayHi();
}

class foo implements fooInterface
{
    function sayHi(){ echo 'hi';}
}
                
没有,靠自觉
重载 由于三种语言均没有显示类型声明,所以没有像C++和Java一样的重载
特殊方法 python定义了许多可以定制类行为的特殊方法
__init__ 构造函数
__del__  析构函数
__str__  用于str()
__unicode__ 用于unicode()
__nonzero__ 用于布尔转换
__len__ 用于len()
__cmp__ 对象比较
__getattr__ 获取不存在的属性时调用
....
                
查看更多
PHP中称这些特殊方法为魔术方法
__construct 构造函数 
__destruct 析构函数
__call 调用不存在的方法时调用 
__get 获取不存在的属性时调用 
__set 设置不存在的属性时调用
__toString 转换成字符串时调用
....
                
查看更多
JS中影响对象行为的特殊方法寥寥
toString 将对象转换为字符串时调用
valueOf 将对象转换为数字时调用
                

正则表达式

Python PHP Javascript
CHANGELOG
------------------------------------------------------------------------
r41 | emptyhua | 2011-01-24 15:11:36 +0800 (Mon, 24 Jan 2011) | 1 line

对象编程部分更新
------------------------------------------------------------------------
r40 | emptyhua | 2011-01-20 15:15:59 +0800 (Thu, 20 Jan 2011) | 1 line

增加了更新日志,对象编程部分更新,这部分都不知该怎么表达了。。
------------------------------------------------------------------------
r39 | emptyhua | 2011-01-18 16:42:58 +0800 (Tue, 18 Jan 2011) | 1 line

增加了部分对象编程
------------------------------------------------------------------------
r38 | emptyhua | 2011-01-17 16:30:33 +0800 (Mon, 17 Jan 2011) | 1 line

增加PPJ文档
------------------------------------------------------------------------