存档:2008年七月

js反射机制

七月 30, 2008 | 数据结构算法 | RSS 2.0

什么是反射机制
反射机制指的是程序在运行时能够获取自身的信息。例如一个对象能够在运行时知道自己有哪些方法和属性。

在JavaScript中利用for(…in…)语句实现反射
在JavaScript中有一个很方便的语法来实现反射,即for(…in…)语句,其语法如下:
for(var p in obj){
      //语句
}
这里var p表示声明的一个变量,用以存储对象obj的属性(方法)名称,有了对象名和属性(方法)名,就可以使用方括号语法来调用一个对象的属性(方法):
for(var p in obj){
      if(typeof(obj[p]==”function”){
             obj[p]();
      }else{
             alert(obj[p]);
      }
}
这段语句遍历obj对象的所有属性和方法,遇到属性则弹出它的值,遇到方法则立刻执行。在后面可以看到,在面向对象的JavaScript程序设计中,反射机制是很重要的一种技术,它在实现类的继承中发挥了很大的作用。


使用反射来传递样式参数
在Ajax编程中,经常要能动态的改变界面元素的样式,这可以通过对象的style属性来改变,比如要改变背景色为红色,可以这样写:
element.style.backgroundColor=”#ff0000″;
其中style对象有很多属性,基本上CSS里拥有的属性在JavaScript中都能够使用。如果一个函数接收参数用用指定一个界面元素的样式,显然一个或几个参数是不能符合要求的,下面是一种实现:
function setStyle(_style){
      //得到要改变样式的界面对象
      var element=getElement();
      element.style=_style;
}
这样,直接将整个style对象作为参数传递了进来,一个style对象可能的形式是:
var style={
      color:#ffffff,
      backgroundColor:#ff0000,
      borderWidth:2px
}
这时可以这样调用函数:
setStyle(style);
或者直接写为:
setStyle({ color:#ffffff,backgroundColor:#ff0000,borderWidth:2px});
这段代码看上去没有任何问题,但实际上,在setStyle函数内部使用参数_style为element.style赋值时,如果element原先已经有了一定的样式,例如曾经执行过:
element.style.height=”20px”;
而_style中却没有包括对height的定义,因此element的height样式就丢失了,不是最初所要的结果。要解决这个问题,可以用反射机制来重写setStyle函数:
function setStyle(_style){
      //得到要改变样式的界面对象
      var element=getElement();
      for(var p in _style){
            element.style[p]=_style[p];
      }
}
程序中遍历_style的每个属性,得到属性名称,然后再使用方括号语法将element.style中的对应的属性赋值为_style中的相应属性的值。从而,element中仅改变指定的样式,而其他样式不会改变,得到了所要的结果。

 

没有评论 »

基础链表

七月 29, 2008 | 数学 | RSS 2.0

创建包含学号、姓名节点的单链表。其节点数任意个,表以学号为序,低学号的在前,高学号的在后,以输入姓名为空作结束。在此链表中,要求删除一个给定姓名的节点,并插入一个给定学号和姓名的节点。
    # include “stdlib.h”
    # include “malloc. h”
    struct node /*节点的数据结构* /
    {
    int num;
    char str[20];
    struct node *next;
    } ;
    / * * * * * * * * * * * * * * * * * * * * * * * * * * * * /
    main( )
    {
    / *函数声明* /

    struct node *creat();
    struct node *insert();
    struct node *delet();
    void print( );
    struct node *head;
    char str[20];
    int n;
    head=NULL; /*做空表* /
    head=creat (head); / *调用函数创建以head 为头的链表* /
    p r i n t ( h e a d ) ;/ *调用函数输出节点* /
    printf(” input inserted num,name:”);
    gets(str); /*输入学号* /
    n=atoi (str);
    gets(str); /*输入姓名* /
    head=insert (head, str, n); 将/*节点插入链表*/
    print (head); / *调用函数输出节点*/
    printf(” input deleted name:”);
    gets(str); /*输入被删姓名* /
    head=delet(head,str); /调*用函数删除节点*/
    print (head); /*调用函数输出节点* /
    r e t u r n ;
    }
    / * * * * * * * * * * * * * * * * * * * * * * /
    / * * * 创建链表* * * * * * * * * * * * /
    struct node *creat(struct node *head)
    {
    char temp[30];
    struct node *pl,*p2;
    pl=p2=(struct node*) malloc(sizeof(struct node));
    printf (”input num, name: ;”)
    printf(”exit:double times Enter!”);
    g e t s ( t e m p ) ;
    gets (p1->str);
    pl->num=atoi (temp);
    p l – > n e x t = N U L L ;
    while (strlen (pl->str)>0
    {
    if (head==NULL) head=pl;
    else p2->next=p1;
    P 2 = p l ;
    pl=(struct node *)malloc(sizeof(struct node));
    printf (”input num, name: “);
    printf(”exit:double times Enter!”);
    g e t s ( t e m p ) ;
    gets(pl ->str);
    p1->num=atoi (temp);
    P 1 – > n e x t = N U L L ;
    }
    return head;
    }
    / * * * * * * * * * * * * * * * * * * * * /
    / * * * * * * * * * * 插入节点* * * * * * * * * * /
    struct node *insert (head, pstr,n);
    struct node *head;
    char *pstr;
    int n;
    {
    struct node *pl,*p2,*p3;
    p1=(struct node*)malloc(sizeof(struct node));
    strcpy (p1->str, pstr);
    p 1 – > n u m = n ;
    p 2 = h e a d ;
    i f ( h e a d = = N U L L )
    {
    h e a d = p l ; p l – > n e x t = N U L L ;
    }
    e l s e
    {
    while (n>p2->num&&p2->next!=NULL)
    {
    p 3 = P 2
    p 2 = p 2 – > n e x t ;
    }
    if (n<=p2->num)
    if (head==p2)
    {
    h e a d = p l ;
    p l – > n e x t = p 2 ;
    }
    else
    {
    p 3 – > n e x t = p l ;
    p l – > n e x t = p 2 ;
    }
    else
    {
    p 2 – > n e x t = p l ;
    p l – > n e x t = N U L L ;
    }
    }
    r e t u r n ( h e a d ) ;
    }
    / * * * * * * * * * * * * * * * * * * * * * * * * * /
    / * * * * * 删除节点* * * * * * * * * * * * * /
    struct node *delet (head, pstr)
    struct node *head;
    char *pstr;
    {
    struct node *temp,*p;
    t e m p = h e a d ;
    if (head==NULL)
    printf(”List is null!”);
    else
    {
    t e m p = h e a d ;
    while (strcmp(temp->str,pstr)!=O&&temp->next!=NULL)
    {
    p = t e m p ;

    t e m p = t e m p – > n e x t ,
    }
    i f ( s t r c m p ( t e m p – > s t r , p s t r ) = = 0 )
    {
    if (temp== head)
    {
    h e a d = h e a d – > n e x t ;
    f r e e ( t e m p ) ;
    }
    else
    {
    p->next =temp->next;
    printf(”delete string :%s”,temp->str);
    f r e e ( t e m p ) ;
    }
    }
    else printf(”no find string!”);
    }
    return(head);
    }
    / * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * /
    / * * * * * * * * * * 链表各节点的输出* * * * * * * * * * /
    void print (struct node *head)
    {
    struct node *temp;
    t e m p = h e a d ;
    printf(” output strings:”);
    while (temp!=NULL)
    {
    p r i n t f ( ” n % d – - – - % s n ” , t e m p – > n u m ,t e m p – > s t r ) ;
    t e m p = t e m p – > n e x t ;
    }
    r e t u r n ;
    }
   BR>if (head==p2)
    {
    h e a d = p l ;
    p l – > n e x t = p 2 ;
    }
    else
    {
    p 3 – > n e x t = p l ;
    p l – > n e x t = p 2 ;
    }
    else
    {
    p 2 – > n e x t = p l ;
    p l – > n e x t = N U L L ;
    }
    }
    r e t u r n ( h e a d ) ;
    }
    / * * * * * * * * * * * * * * * * * * * * * * * * * /
    / * * * * * 删除节点* * * * * * * * * * * * * /
    struct node *delet (head, pstr)
    struct node *head;
    char *pstr;
    {
    struct node *temp,*p;
    t e m p = h e a d ;
    if (head==NULL)
    printf(”List is null!”);
    else
    {
    t e m p = h e a d ;
    while (strcmp(temp->str,pstr)!=O&&temp->next!=NULL)
    {
    p = t e m p ;
    t e m p = t e m p – > n e x t ,
    }
    i f ( s t r c m p ( t e m p – > s t r , p s t r ) = = 0 )
    {
    if (temp== head)
    {
    h e a d = h e a d – > n e x t ;
    f r e e ( t e m p ) ;
    }
    else
    {
    p->next =temp->next;
    printf(”delete string :%s”,temp->str);
    f r e e ( t e m p ) ;
    }
    }
    else printf(”no find string!”);
    }
    return(head);
    }
    / * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * /
    / * * * * * * * * * * 链表各节点的输出* * * * * * * * * * /
    void print (struct node *head)
    {
    struct node *temp;
    t e m p = h e a d ;
    printf(” output strings:”);
    while (temp!=NULL)
    {
    p r i n t f ( ” n % d – - – - % s n ” , t e m p – > n u m ,t e m p – > s t r ) ;

    t e m p = t e m p – > n e x t ;
    }
    r e t u r n ;
    }

 

没有评论 »

几个网站

七月 29, 2008 | mysql | RSS 2.0

http://interface.eyecon.ro/  Jquery interface

http://www.bindows.net/   Javascrīpt

http://www.java125.cn/article.asp?id=2321  Jquery interface 说明

http://fanqiang.chinaunix.net/db/mysql/2006-05-08/4135.shtml  mysql 分区

http://www.phpchina.com/14782/viewspace_21200.html   mysql 优化

http://unix-cd.com/unixcd12/article_4076.html    mysql索引

http://space.itpub.net/11310314/viewspace-155  mysql优化

http://blog.chinaunix.net/u/28922/showart_415710.html mysql锁机制

http://www.phpchina.com/bbs/thread-12284-1-8.html php分页类

http://www.phpchina.com/14112/viewspace_24361.html memory_cache

http://blog.s135.com/  系统管理

http://www.phpchina.com/bbs/viewthread.php?tid=51684  多文件上传类型判断

http://soft.zdnet.com.cn/software_zone/2007/0306/379968.shtml  TFS入门

http://www.ajaxload.info/#preview  gif进度条自动生成

http://www.phpchina.com/bbs/thread-15486-1-2.html  phpMVC模式

http://www.phpframeworks.com/  php框架

http://www.phpchina.com/29828/viewspace_27817.html ajax技术(跨子域名)

http://man.lupaworld.com/content/w3c/w3c2.html  xhtml教程

http://www.knowsky.com/344533.html php5 class

http://www.ibm.com/developerworks/cn/xml/x-html5/  IBM中国 好东西太多了

http://edu.itbulo.com/pro/php/phpsl/Index.htm   php 实例

http://www.phpchina.com/viewnews_562.html  PHPchina的

http://www.chedong.com/blog/  车东的

http://www.dbanotes.net/ dbanote

http://blog.s135.com/  系统维护

http://hi.baidu.com/1860_yk/blog/item/f5e00bcc0e14031400e92874.html  fsockopen and post

http://blog.s135.com/read.php/311.htm   张宴php多进程、linux守护进程

 

没有评论 »

php的错误吗?

七月 25, 2008 | 网站架构 | RSS 2.0

 $array = array(’dog’ => ‘animal’);
 $array['dog'] = null;
 var_dump(isset($array['dog'])); // this will be false
 var_dump(array_key_exists(’dog’, $array)); // this will be true
 EXIT;

没有评论 »

普希金

七月 21, 2008 | mysql | RSS 2.0

假如生活欺骗了你,
不要悲伤,不要心急,
阴郁的日子需要镇静,
相信吗?
那愉快的日子即将来临,
心永远憧憬未来,
现在却常是阴沉,
一切都是瞬间,一切都是过去,
而那过去了的,
就会变成亲切的怀念

没有评论 »

php魔法函数

七月 16, 2008 | linux | RSS 2.0

PHP处理对象部分的内核完全重新开发过,提供更多功能的同时也提高了性能。在以前版本的php中,处理对象和处理基本类型(数字,字符串)的方式是一样的。这种方式的缺陷是:当将对象赋值给一个变量时,或者通过参数传递对象时,对象将被完全拷贝一份。在新的版本里,上述操作将传递引用(可以把引用理解成对象的标识符),而非值。
很多PHP程序员可能甚至没有察觉到老的对象处理方式。事实上,大多数的php应用都可以很好地运行。或者仅仅需要很少的改动。
私有和受保护成员
PHP5引入了私有和受保护成员变量的概念。我们可以用它来定义类成员的可见性。
例子
受保护成员可以被子类访问, 而私有成员只能被类本身访问。


代码:——————————————————————————–

<?php
class MyClass {
private $Hello = “Hello, World!”;
protected $Bar = “Hello, Foo!”;
protected $Foo = “Hello, Bar!”;

function printHello() {
print “MyClass::printHello() ” . $this->Hello;
print “MyClass::printHello() ” . $this->Bar;
print “MyClass::printHello() ” . $this->Foo;
}
}

class MyClass2 extends MyClass {
protected $Foo;

function printHello() {
MyClass::printHello(); /* Should print */
print “MyClass2::printHello() ” . $this->Hello; /* Shouldn’t print out anything */
print “MyClass2::printHello() ” . $this->Bar; /* Shouldn’t print (not declared)*/
print “MyClass2::printHello() ” . $this->Foo; /* Should print */
}
}

$obj = new MyClass();
print $obj->Hello; /* Shouldn’t print out anything */
print $obj->Bar; /* Shouldn’t print out anything */
print $obj->Foo; /* Shouldn’t print out anything */
$obj->printHello(); /* Should print */

$obj = new MyClass2();
print $obj->Hello; /* Shouldn’t print out anything */
print $obj->Bar; /* Shouldn’t print out anything */
print $obj->Foo; /* Shouldn’t print out anything */
$obj->printHello();
?>
——————————————————————————–

私有方法和受保护方法
PHP5也引入了私有方法和受保护方法的概念。
例子:

代码:——————————————————————————–

<?php
class Foo {
private function aPrivateMethod() {
echo “Foo::aPrivateMethod() called.”;
}

protected function aProtectedMethod() {
echo “Foo::aProtectedMethod() called.”;
$this->aPrivateMethod();
}
}

class Bar extends Foo {
public function aPublicMethod() {
echo “Bar::aPublicMethod() called.”;
$this->aProtectedMethod();
}
}

$o = new Bar;
$o->aPublicMethod();
?>
——————————————————————————–

以前的不使用类的老代码,没有访问修饰符(public, protected, private)的代码可以不经改动运行。
抽象类和抽象方法
Php5也引入了抽象类和抽象方法的概念。抽象方法只是声明了方法的签名并不提供它的实现。包含抽象方法的类必须被声明成抽象类。
例子:

代码:——————————————————————————–

<?php
abstract class AbstractClass {
abstract public function test();
}

class ImplementedClass extends AbstractClass {
public function test() {
echo “ImplementedClass::test() called.”;
}
}

$o = new ImplementedClass;
$o->test();
?>
——————————————————————————–

抽象类不能被实例化。以前的不使用抽象类的老代码可以不经改动运行。
接口
Php5引入了接口。一个类可以实现多个接口。
例子:

代码:——————————————————————————–

<?php
interface Throwable {
public function getMessage();
}

class MyException implements Throwable {
public function getMessage() {
// …
}
}
?>
——————————————————————————–

以前的不使用接口的老代码可以不经改动运行

类的型别提示
PHP5依然是弱类型的,不过在定义函数参数时,可以使用类的型别提示来声明期望传入的对象类型
Example

代码:——————————————————————————–

<?php
interface Foo {
function a(Foo $foo);
}

interface Bar {
function b(Bar $bar);
}

class FooBar implements Foo, Bar {
function a(Foo $foo) {
// …
}

function b(Bar $bar) {
// …
}
}

$a = new FooBar;
$b = new FooBar;

$a->a($b);
$a->b($b);
?>
——————————————————————————–

和其他强类型语言一样,php5类的型别提示在运行期间检查而非编译期间检查。即:

代码:——————————————————————————–

<?php
function foo(ClassName $object) {
// …
}
?>
和下面的代码是一样的:
<?php
function foo($object) {
if (!($object instanceof ClassName)) {
die(”Argument 1 must be an instance of ClassName”);
}
}
?>
——————————————————————————–

这个语法只适用于类,不适用于内建类型。
Final

PHP 5 引入了final关键字来声明final成员和final方法。final成员和final方法不能被子类覆盖。
Example

代码:——————————————————————————–

<?php
class Foo {
final function bar() {
// …
}
}
?>
——————————————————————————–

更进一步,可以把类声明成final。将类声明成final可以阻止这个类被继承。final类里面的方法缺省地都是final的,无需再声明一次。
Example

代码:——————————————————————————–

<?php
final class Foo {
// class definition
}

// the next line is impossible
// class Bork extends Foo {}
?>
——————————————————————————–

属性不能定义成为final.
以前的不使用final的老代码可以不经改动运行.
对象克隆
Php4没有提供一种机制来让用户自己定义复制构造子(copy constructor)控制对象的复制过程。Php4做二进制的拷贝,因而很精确地复制了对象的所有属性。
精确地复制对象的所有属性可能并不是我们一直想要的。有个例子可以很好地说明我们确实需要复制构造子:比如一个GTK Window的对象 a。 a持有它所需要的全部资源。当复制的这个GTK Window到对象b时候,我们更希望b持有新的资源对象。再举个例子:对象a包含了一个对象c, 当你把对象a 复制到对象c的时候。我们可能更希望对象b包含一个新的对象c的copy, 而不是一个对象c的引用。(译者注:这里所说的就是浅克隆和深克隆。)
对象的复制是通过clone这个关键字达到的(Clone调用被克隆对象的__clone()方法)。对象的__clone方法不能够直接被调用。

代码:——————————————————————————–


<?php
$copy_of_object = clone $object;
?>
——————————————————————————–

当developer创建对象的一份拷贝的时候,php5将会检查 __clone()方法是否存在。如果不存在,那么它就会呼叫缺省的__clone()方法,复制对象的所有属性。如果__clone()方法已经定义过,那么_clone()方法就会负责设置新对象的属性。为了方便起见,Engine会缺省地复制所有的属性。所以在__clone()方法中,只需要覆盖那些需要更改的属性就可以了。如下:
Example

代码:——————————————————————————–

<?php
class MyCloneable {
static $id = 0;

function MyCloneable() {
$this->id = self::$id++;
}

function __clone() {
$this->address = “New York”;
$this->id = self::$id++;
}
}

$obj = new MyCloneable();

$obj->name = “Hello”;
$obj->address = “Tel-Aviv”;

print $obj->id . “”;

$obj_cloned = clone $obj;

print $obj_cloned->id . “”;
print $obj_cloned->name . “”;
print $obj_cloned->address . “”;
?>
——————————————————————————–

统一构造函数
Php5允许开发者声明一个类的构造方法。拥有构造方法的类在每次创建新的对象的时候都会呼叫这个方法,因此构造方法适合对象在被使用之前的初始化工作
Php4中,构造方法的名称和类的名称一样。考虑到从子类构造方法呼叫父类构造方法的情况是非常普遍的,而将类从一个继承体系中搬迁引起的父类变更就常常导致需要更改类的构造方法,php4的做法显然是不太合理的。
Php5引入了一个声明构建函数的标准方法: __construct().如下:
Example

代码:——————————————————————————–

<?php
class BaseClass {
function __construct() {
print “In BaseClass constructor”;
}
}

class SubClass extends BaseClass {
function __construct() {
parent::__construct();
print “In SubClass constructor”;
}
}

$obj = new BaseClass();
$obj = new SubClass();
?>
——————————————————————————–

为保持向后的兼容性,如果php5不能够找到 __construct(),它会寻找老式的构造方法,即与类同名的方法。简单的说,只有当老代码里包含了一个__construct()方法的时候,才存在一个兼容性的问题。
析构方法
对于面向对象的编程来说,可以定义析构方法是非常有用的一个功能。析构方法可以用来记录调试信息,关闭数据库连接等等一些清除收尾的工作。Php4中没有析构方法,尽管php4已经支持可以注册一个函数以便请求结束的时候被调用。
Php5引进的析构方法的概念和其他面向对象的语言(比如java)是一致的。当指向这个对象的最后一个引用被销毁的时候,析构方法被调用,调用完成后释放内存。注意:析构方法不接受任何参数。
Example

代码:——————————————————————————–

<?php
class MyDestructableClass {
function __construct() {
print “In constructor”;
$this->name = “MyDestructableClass”;
}

function __destruct() {
print “Destroying ” . $this->name . “”;
}
}

$obj = new MyDestructableClass();
?>
——————————————————————————–

和构建方法一样,父类的析构方法也不会被隐含调用。子类可以在自己的析构方法通过调用parent::__destruct()来显式地调用它。
Constants
Php5引入了class级别的常量。

代码:——————————————————————————–

<?php
class Foo {
const constant = “constant”;
}

echo “Foo::constant = ” . Foo::constant . “”;
?>
——————————————————————————–

老的没有使用const的代码仍然正常运行。
Exceptions
Php4没有异常控制。Php5引入了和其它语言(java)相似的异常控制模式。应该注意的是php5里面支持捕捉全部异常,但是不支持finally子句。
在catch语句块里面,可以重新抛出异常。也可以有多个catch语句,在这种情况下,被捕捉到的异常从上往下依次比较和catch语句比较异常,第一个类型匹配的catch语句将会被执行。如果一直搜索到底还没有发现匹配的catch子句,则寻找下一个try/catch语句。最后不能捕捉的异常将被显示出来。如果异常被捕捉,那么程序会接着catch语句块的下面开始执行。
Example

代码:——————————————————————————–

<?php
class MyException {
function __construct($exception) {
$this->exception = $exception;
}

function Display() {
print “MyException: $this->exception”;
}
}

class MyExceptionFoo extends MyException {
function __construct($exception) {
$this->exception = $exception;
}

function Display() {
print “MyException: $this->exception”;
}
}

try {
throw new MyExceptionFoo(’Hello’);
}
catch (MyException $exception) {
$exception->Display();
}
catch (Exception $exception) {
echo $exception;
}
?>
——————————————————————————–

上面的例子表明可以定义一个并不继承自 Exception的异常类,但是,最好还是从Exception继承并定义自己的异常。这是因为系统内建的Exception类能够收集到很多有用的信息, 而不继承它的异常类是得不到这些信息的。下面的php代码模仿了系统内建Exception类。每个属性后面都加了注释。每个属性都有一个getter,由于这些getter方法经常被系统内部处理调用,所以这些方法被标明了final。
Example

代码:——————————————————————————–

<?php
class Exception {
function __construct(string $message=NULL, int code=0) {
if (func_num_args()) {
$this->message = $message;
}
$this->code = $code;
$this->file = __FILE__; // of throw clause
$this->line = __LINE__; // of throw clause
$this->trace = debug_backtrace();
$this->string = StringFormat($this);
}

protected $message = ‘Unknown exception’; // exception message
protected $code = 0; // user defined exception code
protected $file; // source filename of exception
protected $line; // source line of exception

private $trace; // backtrace of exception
private $string; // internal only!!

final function getMessage() {
return $this->message;
}
final function getCode() {
return $this->code;
}
final function getFile() {
return $this->file;
}
final function getTrace() {
return $this->trace;
}
final function getTraceAsString() {
return self::TraceFormat($this);
}
function _toString() {
return $this->string;
}
static private function StringFormat(Exception $exception) {
// … a function not available in PHP scripts
// that returns all relevant information as a string
}
static private function TraceFormat(Exception $exception) {
// … a function not available in PHP scripts
// that returns the backtrace as a string
}
}
?>
——————————————————————————–

如果我们定义的一异常类都是继承自Exception基类
无兼容性问题。老的代码不会受到这一特性的影响。
Dereferencing objects returned from functions
Php4中不能再次引用函数返回的对象以进一步呼叫返回对象的方法,而php5是可以的。

代码:——————————————————————————–

<?php
class Circle {
function draw() {
print “Circle”;
}
}

class Square {
function draw() {
print “Square”;
}
}

function ShapeFactoryMethod($shape) {
switch ($shape) {
case “Circle”:
return new Circle();
case “Square”:
return new Square();
}
}

ShapeFactoryMethod(”Circle”)->draw();
ShapeFactoryMethod(”Square”)->draw();
?>
——————————————————————————–

静态成员变量能够被初始化。
Example

代码:——————————————————————————–

<?php
class foo {
static $my_static = 5;
public $my_prop = ‘bla’;
}

print foo::$my_static;
$obj = new foo;
print $obj->my_prop;
?>
——————————————————————————–

静态方法
PHP 5 引入了静态方法,可以在不实例化类的情况下呼叫静态方法。
Example

代码:——————————————————————————–

<?php
class Foo {
public static function aStaticMethod() {
// …
}
}

Foo::aStaticMethod();
?>
——————————————————————————–

伪变量$this不能够在静态方法方法中使用。
instanceof
Php5引入了instanceof关键字,允许用它来测试一个对象是一个类的实例,或者是一个派生类的实例,或者实现了某个接口
Example

代码:——————————————————————————–

<?php
class baseClass { }

$a = new baseClass;

if ($a instanceof baseClass) {
echo “Hello World”;
}
?>
——————————————————————————–

Static function variables
现在,静态变量在编译阶段处理。因此程序员可以通过引用为静态变量赋值。这可以改善性能,不过,不能够使用对静态变量的间接引用了。
按引用传递的函数参数现在也可以设置缺省值了。
Example

代码:——————————————————————————–

<?php
function my_function(&$var = null) {
if ($var === null) {
die(”$var needs to have a value”);
}
}
?>
——————————————————————————–

__autoload()
__autoload() 拦截函数在一个未声明的类被初始化的时候自动调用。该类的名字会被自动传递给__autoload()函数。而__autoload()也只有这么唯一的一个参数。
Example

代码:——————————————————————————–

<?php
function __autoload($className) {
include_once $className . “.php”;
}

$object = new ClassName;
?>
——————————————————————————–

可重载的方法呼叫和属性访问
方法呼叫和属性访问都能够通过__call, __get() and __set()方法重载。
Example: __get() and __set()

代码:——————————————————————————–

<?php
class Setter {
public $n;
public $x = array(”a” => 1, “b” => 2, “c” => 3);

function __get($nm) {
print “Getting [$nm]“;

if (isset($this->x[$nm])) {
$r = $this->x[$nm];
print “Returning: $r”;
return $r;
} else {
print “Nothing!”;
}
}

function __set($nm, $val) {
print “Setting [$nm] to $val”;

if (isset($this->x[$nm])) {
$this->x[$nm] = $val;
print “OK!”;
} else {
print “Not OK!”;
}
}
}

$foo = new Setter();
$foo->n = 1;
$foo->a = 100;
$foo->a++;
$foo->z++;
var_dump($foo);
?>
——————————————————————————–

Example: __call()

代码:——————————————————————————–

<?php
class Caller {
private $x = array(1, 2, 3);

function __call($m, $a) {
print “Method $m called:”;
var_dump($a);
return $this->x;
}
}

$foo = new Caller();
$a = $foo->test(1, “2″, 3.4, true);
var_dump($a);
?>
——————————————————————————–

迭代
当和foreach一起使用对象的时候,迭代的方式被重载过了。缺省的行为是迭代类的所有属性。
Example

代码:——————————————————————————–

<?php
class Foo {
public $x = 1;
public $y = 2;
}

$obj = new Foo;

foreach ($obj as $prp_name => $prop_value) {
// using the property
}
?>
——————————————————————————–

一个类的所有对象都能够被迭代浏览到, 如果这个类实现了一个空的接口:Traversable. 换句话说,实现了Traversable接口的类可以和foreach一起使用。
接口 IteratorAggregate 和Iterator允许指定类的对象在代码中如何迭代。IteratorAggregate接口有一个方法:getIterator() 必须返回一个数组
Example

代码:——————————————————————————–

<?php
class ObjectIterator implements Iterator {

private $obj;
private $num;

function __construct($obj) {
$this->obj = $obj;
}
function rew …

没有评论 »

innodb表如何更快得到count(*)结果

七月 9, 2008 | 数据结构算法 | RSS 2.0

[InnoDB系列系列] — innodb表如何更快得到count(*)结果

周二, 2008/06/24 – 17:17 — yejr

作/译者:叶金荣(Email: ),来源:http://imysql.cn,转载请注明作/译者和出处,并且不能用于商业用途,违者必究。

起因:在innodb表上做count(*)统计实在是太慢了,因此想办法看能不能再快点。

现象:先来看几个测试案例,如下

一、 sbtest 表上的测试

show create table sbtestG

*************************** 1. row ***************************

       Table: sbtest

Create Table: CREATE TABLE `sbtest` (

  `aid` bigint(20) unsigned NOT NULL auto_increment,

  `id` int(10) unsigned NOT NULL default ‘0′,

  `k` int(10) unsigned NOT NULL default ‘0′,

  `c` char(120) NOT NULL default ”,

  `pad` char(60) NOT NULL default ”,

  PRIMARY KEY  (`aid`),

  KEY `k` (`k`),

  KEY `id` (`id`)

) ENGINE=InnoDB AUTO_INCREMENT=1000001 DEFAULT CHARSET=latin1

 

show index from sbtest;

+——–+————+———-+————–+————-+———–+————-+———-+——–+——+————+———+

| Table  | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |

+——–+————+———-+————–+————-+———–+————-+———-+——–+——+————+———+

| sbtest |          0 | PRIMARY  |            1 | aid         | A         |     1000099 |     NULL | NULL   |      | BTREE      |         |

| sbtest |          1 | k        |            1 | k           | A         |          18 |     NULL | NULL   |      | BTREE      |         |

| sbtest |          1 | id       |            1 | id          | A         |     1000099 |     NULL | NULL   |      | BTREE      |         |

+——–+————+———-+————–+————-+———–+————-+———-+——–+——+————+———+

填充了 1000万条 记录。

1、 直接 count(*)

explain SELECT COUNT(*) FROM sbtest;

+—-+————-+——–+——-+—————+———+———+——+———+————-+

| id | select_type | table  | type  | possible_keys | key     | key_len | ref  | rows    | Extra       |

+—-+————-+——–+——-+—————+———+———+——+———+————-+

|  1 | SIMPLE      | sbtest | index | NULL          | PRIMARY | 8       | NULL | 1000099 | Using index |

+—-+————-+——–+——-+—————+———+———+——+———+————-+

 

SELECT COUNT(*) FROM sbtest;

+———-+

| COUNT(*) |

+———-+

|  1000000 |

+———-+

1 row in set (1.42 sec)

可以看到,如果不加任何条件,那么优化器优先采用 primary key 来进行扫描。

2、count(*) 使用 primary key 字段做条件

explain SELECT COUNT(*) FROM sbtest WHERE aid>=0;

+—-+————-+——–+——-+—————+———+———+——+——–+————————–+

| id | select_type | table  | type  | possible_keys | key     | key_len | ref  | rows   | Extra                    |

+—-+————-+——–+——-+—————+———+———+——+——–+————————–+

|  1 | SIMPLE      | sbtest | range | PRIMARY       | PRIMARY | 8       | NULL | 485600 | Using where; Using index |

+—-+————-+——–+——-+—————+———+———+——+——–+————————–+

 

SELECT COUNT(*) FROM sbtest WHERE aid>=0;

+———-+

| COUNT(*) |

+———-+

|  1000000 |

+———-+

1 row in set (1.39 sec)

可以看到,尽管优化器认为只需要扫描 485600 条记录(其实是索引),比刚才少多了,但其实仍然要做全表(索引)扫描。因此耗时和第一种相当。

3、 count(*) 使用 secondary index 字段做条件

explain SELECT COUNT(*) FROM sbtest WHERE id>=0;

+—-+————-+——–+——-+—————+——+———+——+——–+————————–+

| id | select_type | table  | type  | possible_keys | key  | key_len | ref  | rows   | Extra                    |

+—-+————-+——–+——-+—————+——+———+——+——–+————————–+

|  1 | SIMPLE      | sbtest | range | id            | id   | 4       | NULL | 500049 | Using where; Using index |

+—-+————-+——–+——-+—————+——+———+——+——–+————————–+

 

SELECT COUNT(*) FROM sbtest WHERE id>=0;

+———-+

| COUNT(*) |

+———-+

|  1000000 |

+———-+

1 row in set (0.43 sec)

可以看到,采用这种方式查询会非常快。

有人也许会问了,会不会是因为 id 字段的长度比 aid 字段的长度来的小,导致它扫描起来比较快呢?先不着急下结论,咱们来看看下面的测试例子。

二、 sbtest1 表上的测试

show create table sbtest1G

*************************** 1. row ***************************

       Table: sbtest1

Create Table: CREATE TABLE `sbtest1` (

  `aid` int(10) unsigned NOT NULL AUTO_INCREMENT,

  `id` bigint(20) unsigned NOT NULL DEFAULT ‘0′,

  `k` int(10) unsigned NOT NULL DEFAULT ‘0′,

  `c` char(120) NOT NULL DEFAULT ”,

  `pad` char(60) NOT NULL DEFAULT ”,

  PRIMARY KEY (`aid`),

  KEY `k` (`k`),

  KEY `id` (`id`)

) ENGINE=InnoDB AUTO_INCREMENT=1000001 DEFAULT CHARSET=latin1

 

show index from sbtest1;

+———+————+———-+————–+————-+———–+————-+———-+——–+——+————+———+

| Table   | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |

+———+————+———-+————–+————-+———–+————-+———-+——–+——+————+———+

| sbtest1 |          0 | PRIMARY  |            1 | aid         | A         |     1000099 |     NULL | NULL   |      | BTREE      |         |

| sbtest1 |          1 | k        |            1 | k           | A         |          18 |     NULL | NULL   |      | BTREE      |         |

| sbtest1 |          1 | id       |            1 | id          | A         |     1000099 |     NULL | NULL   |      | BTREE      |         |

+———+————+———-+————–+————-+———–+————-+———-+——–+——+————+———+

这个表里,把 aid 和 id 的字段长度调换了一下,也填充了 1000万条 记录。

1、 直接 count(*)

explain SELECT COUNT(*) FROM sbtest1;

+—-+————-+———+——-+—————+———+———+——+———+————-+

| id | select_type | table   | type  | possible_keys | key     | key_len | ref  | rows    | Extra       |

+—-+————-+———+——-+—————+———+———+——+———+————-+

|  1 | SIMPLE      | sbtest1 | index | NULL          | PRIMARY | 4       | NULL | 1000099 | Using index |

+—-+————-+———+——-+—————+———+———+——+———+————-+

 

SELECT COUNT(*) FROM sbtest1;

+———-+

| COUNT(*) |

+———-+

|  1000000 |

+———-+

1 row in set (1.42 sec)

可以看到,如果不加任何条件,那么优化器优先采用 primary key 来进行扫描。

2、count(*) 使用 primary key 字段做条件

explain SELECT COUNT(*) FROM sbtest1 WHERE aid>=0;

+—-+————-+———+——-+—————+———+———+——+——–+————————–+

| id | select_type | table   | type  | possible_keys | key     | key_len | ref  | rows   | Extra                    |

+—-+————-+———+——-+—————+———+———+——+——–+————————–+

|  1 | SIMPLE      | sbtest1 | range | PRIMARY       | PRIMARY | 4       | NULL | 316200 | Using where; Using index |

+—-+————-+———+——-+—————+———+———+——+——–+————————–+

1 row in set (0.00 sec)

 

SELECT COUNT(*) FROM sbtest1 WHERE aid>=0;

+———-+

| COUNT(*) |

+———-+

|  1000000 |

+———-+

1 row in set (1.42 sec)

可以看到,尽管优化器认为只需要扫描 485600 条记录(其实是索引),比刚才少多了,但其实仍然要做全表(索引)扫描。因此耗时和第一种相当。

3、 count(*) 使用 secondary index 字段做条件

explain SELECT COUNT(*) FROM sbtest1 WHERE id>=0;

+—-+————-+———+——-+—————+——+———+——+——–+————————–+

| id | select_type | table   | type  | possible_keys | key  | key_len | ref  | rows   | Extra                    |

+—-+————-+———+——-+—————+——+———+——+——–+————————–+

|  1 | SIMPLE      | sbtest1 | range | id            | id   | 8       | NULL | 500049 | Using where; Using index |

+—-+————-+———+——-+—————+——+———+——+——–+————————–+

1 row in set (0.00 sec)

 

SELECT COUNT(*) FROM sbtest1 WHERE id>=0;

+———-+

| COUNT(*) |

+———-+

|  1000000 |

+———-+

1 row in set (0.45 sec)

可以看到,采用这种方式查询会非常快。

上面的所有测试,均在 mysql 5.1.24 环境下通过,并且每次查询前都重启了 mysqld。

可以看到,把 aid 和 id 的长度调换之后,采用 secondary index 查询仍然是要比用 primary key 查询来的快很多。看来主要不是字段长度引起的索引扫描快慢,而是采用 primary key 以及 secondary index 引起的区别。那么,为什么用 secondary index 扫描反而比 primary key 扫描来的要快呢?我们就需要了解innodb的 clustered index 和 secondary index 之间的区别了。

innodb 的 clustered index 是把 primary key 以及 row data 保存在一起的,而 secondary index 则是单独存放,然后有个指针指向 primary key。因此,需要进行 count(*) 统计表记录总数时,利用 secondary index 扫描起来,显然更快。而primary key则主要在扫描索引,同时要返回结果记录时的作用较大,例如:

SELECT * FROM sbtest WHERE aid = xxx;

那既然是使用 secondary index 会比 primary key 更快,为何优化器却优先选择 primary key 来扫描呢,Heikki Tuuri 的回答是:

in the example table, the secondary index is inserted into in a perfect order! That is

very unusual. Normally the secondary index would be fragmented, causing random disk I/O,

and the scan would be slower than in the primary index.

 

I am changing this to a feature request: keep ‘clustering ratio’ statistics on a secondary

index and do the scan there if the order is almost the same as in the primary index. I

doubt this feature will ever be implemented, though.

没有评论 »

十八年换来和你一起喝咖啡

七月 6, 2008 | mysql | RSS 2.0

3年前,麦子的一篇《我奋斗了18年才和你坐在一起喝咖啡》引起多少共鸣,一个农家子弟经过18年的奋斗,才取得和大都会里的同龄人平起平坐的权利,一代人的真实写照。然而,3年过去,我恍然发觉,他言之过早。18年又如何?再丰盛的年华叠加,我仍不能和你坐在一起喝咖啡。
  
  那年我25,无数个夙兴夜寐,换来一个硕士学位,额上的抬头纹分外明显,脚下却半步也不敢停歇。如果不想让户口打回原籍,子子孙孙无穷匮,得赶紧地找份留京工作。你呢?你不着急,魔兽世界和红色警报?早玩腻了!你野心勃勃地筹划着“创业创业”。当时李彦宏、陈天桥、周云帆,牛人们还没有横空出世,百度、Google、完美时空更是遥远的名词,可青春所向披靡不可一世,你在校园里建起配送网站,大张旗鼓地招兵买马,大小媒体的记者蜂拥而至。334寝室很快在全楼名噪一时,小姑娘们从天南地北寄来粉粉的信纸,仰慕地写道:“从报上得知你的精彩故事……”得空,爬上楼顶吹吹风,你眉飞色舞地转向我,以照顾自己人的口气说,兄弟,一起发财如何?
  
  好呀,可惜,我不能。创业于你,是可进可退可攻可守的棋,启动资金有三姑六眷帮忙筹集,就算铩羽而归,父母那三室一厅、温暖的灶台也永不落空。失败于我,意味着覆水难收一败涂地,每年夏天,为了节省三五百块钱的机器钱,爹娘要扛着腰肌劳损在大日头下收割5亩农田。我穿着借来的西服完成了第一次面试,戴着借来的手表与心爱的女孩进行了第一次约会。当你拿到了第一笔投资兴奋地报告全班时,我冷静地穿越大半个北京城,去做最后一份家教。没错,“这活儿技术含量忒低”,但在第一个月工资下发前,我租来的立锥之地与口粮全靠它维持。
  
  不多久,互联网就遭遇了寒流,你也对创业意兴阑珊,进了家国有性质的通信公司,我被一家外企聘用。坐井观天的我,竟傻傻地以为扳回了一局。明面上的工资,我比你超出一截,税后8000,出差住5星级宾馆,一年带薪休假10天。玩命一样地投入工作,坚信几年后也有个童话般的结尾,“和公主过上幸福的生活”。
  
  好景不长,很快,我明白了为什么大家说白领是句骂人的话。写字楼的套餐,标价35,几乎没人搭理它。午餐时间,最抢手的是各层拐角处的微波炉,“白领”们端着带来的便当,排起了长长的队伍。后来,物业允许快餐公司入住,又出现了“千人排队等丽华”的盛况。这些月入近万的人士节约到抠门的程度。一位同事,10块钱的感冒药都找保险公司理赔;另一位,在脏乱差的火车站耗上3个小时,为的是18:00后返程能多得150元的晚餐补助。
  
  这幕幕喜剧未能令我发笑,我读得懂,每个数字后都凝结着加班加点与忍气吞声;俯首帖耳被老板盘剥,为的是一平米一平米构筑起自己的小窝。白手起家的过程艰辛而漫长,整整3年,我没休过一次长假没吃过一回鸭脖子;听到“华为25岁员工胡新宇过劳死”的新闻,也半点儿不觉得惊讶,以血汗、青春换银子的现象在这个行业太普遍了。下次,当你在上地看见一群人穿着西装革履拎着IBM笔记本奋力挤上4毛钱的公交车,千万别奇怪,我们就是一群IT民工。
  
  惟一让人欣慰的是,我们离理想中的目标一步步靠近。
  
  突如其来地,你的喜讯从天而降:邀请大家周末去新居暖暖房。怎么可能?你竟比我快?可豁亮的100多平方米、红苹果家具、37寸液晶大彩电无可质疑地摆在眼前。你轻描淡写地说,老头子给了10万,她家里也给了10万,老催着我们结婚……回家的路上,女朋友郁郁不说话,她和我一样,来自无名的山城。我揽过她的肩膀,鼓励她也是鼓励自己,没关系,我们拿时间换空间。
  
  蜜月你在香港过的,轻而易举地花掉了半年的工资,回来说,意思不大,不像TVB电视里拍的那样美轮美奂;我的婚礼,在家乡的土路、乡亲的围观中巡游,在低矮昏暗的老房子里拜了天地,在寒冷的土炕上与爱人相拥入眠。幸运的是,多年后黯淡的图景化作妻子博客里光芒四射的图画,她回味:“有爱的地方,就有天堂。”
  
  我们都想给深爱的女孩以天堂,天堂的含义却迥然不同。你的老婆当上了全职太太,每天用电驴下载《老友记》和《越狱》;我也想这么来着,老婆不同意,你养我,谁养我爸妈?不忍心让你一个人养7个人。当你的女孩敷着倩碧面膜舒服地翘起脚,我的女孩却在人海中顽强地搏杀。
  
  两个人赚钱的速度快得多。到2004年年底,我们也攒到了人生中第一个10万,谁知中国的楼市在此时被魔鬼唤醒,海啸般狂飙突进,摧毁一切渺小虚弱的个体。2005年3月,首付还够买西四环的郦城,到7月,只能去南城扫楼了。我们的积蓄本来能买90平方米的两居来着,9月中旬,仅仅过去2个月,只够买80多平。
  
  没学过经济学原理?没关系。生活生动地阐释了什么叫资产泡沫与流动性泛滥。这时专家跳出来发言了,“北京房价应该降30%,上海房价应该降40%。”要不,再等等?我险些栖身于温吞的空方阵营,是你站出来指点迷津:赶快买,房价还会涨。买房的消息传回老家,爹娘一个劲儿地唏嘘:抵得上俺们忙活半年。在他们看来,7500元一平方米是不可思议的天价。3年后的2008,师弟们纷纷感叹,你赚大发了,四环内均价1万4,已无楼可买。
  
  几天前,我看见了水木上一句留言,颇为感慨:“工作5年还没买房真活该,2003年正是楼市低迷与萧条之时。等到今天,踏空的不仅是黄金楼市,更是整个人生。”
  
  真要感谢你,在我不知理财为何物之时,你早早地告诉我什么叫消费什么叫投资。
  
  并非所有人都拥有前瞻的眼光和投资的观念。许多和我一样来自小地方、只知埋头苦干的兄弟们,太过关注脚下的麦田,以至于错过一片璀璨的星空。你的理论是,赚钱是为了花,只有在流通中才能增值,买到喜爱的商品,让生活心旷神怡。而我的农民兄弟——这里特指是出身农家毕业后留在大城市的兄弟,习惯于把人民币紧紧地捏在手中。存折数字的增长让他们痴迷。该买房时,他们在租房;该还贷时,他们宁可忍受7%的贷款利率,也要存上5年的定期。辛苦赚来的银子在等待中缩水贬值。他们往往在房价的巅峰处,无可奈何地接下最后一棒;也曾天真地许愿,赚够100万就回家买房。可等到那一天真的到来,老家的房价,二线、三线城市甚至乡镇的都已疯长。
  
  这便是我和你的最大差别,根深蒂固的分歧、不可逾越的鸿沟也在于此。我曾经以为,学位、薪水、公司名气一样了,我们的人生便一样了。事实上,差别不体现在显而易见的符号上,而是体现在世世代代的传承里,体现在血液里,体现在头脑中。18年的积累,家庭出身、生活方式、财务观念,造就了那样一个你,也造就了这样一个我,造就了你的疏狂佻达与我的保守持重。当我还清贷款时,你买了第二套住房;上证指数6000点,当我好容易试水成为股民,你清仓离场,转投金市;我每月寄1000元回去,承担起赡养父母的责任,你笑嘻嘻地说,养老,我不啃老就不错了;当我思考着要不要生孩子、养孩子的成本会在多大程度上折损生活品质时,4个老人已出钱出力帮你抚养起独二代;黄金周去一趟九寨沟挺好的了,你不满足,你说德国太拘谨美国太随意法国才是你向往的时尚之都……
  
  我的故事,是一代“移民”的真实写照——迫不得已离乡背井,祖国幅员辽阔,我却像候鸟一样辗转迁徙,择木而栖。现行的社会体制,注定了大城市拥有更丰富的教育资源、医疗资源、生活便利。即便取得了一纸户口,跻身融入的过程依然是充满煎熬,5年、10年乃至更长时间的奋斗才获得土著们唾手可得的一切。曾经愤慨过,追寻过,如今,却学会了不再抱怨,在一个又一个缝隙间心平气和。差距固然存在,但并不令人遗憾,正是差距和为弥补差距所付出的努力,加强了生命的张力,使其更有层次更加多元。
  
  可以想见的未来是,有一天我们的后代会相聚于迪斯尼(这点自信我还是有的),讲起父亲的故事,我的那一个,虽然不一定更精致更华彩,无疑曲折有趣得多。那个故事,关于独立、勇气、绝地反弹、起死回生,我给不起儿子名车豪宅,却能给他一个不断成长的心灵。我要跟他说,无论贫穷富贵,百万家资或颠沛流离,都要一样地从容豁达。
  
  至此,喝不喝咖啡又有什么打紧呢?生活姿态的优雅与否,不取决于你所坐的位置、所持的器皿、所付的茶资。它取决于你品茗的态度。
  
  我奋斗了18年,不是为了和你一起喝咖啡。

没有评论 »