PHP OOP思想之抽象方法和抽象类(abstract)

By heiry on 2009-10-21 [ in 技术 ]

在OOP思想中,一个类可以有一个或多个子类,而每个类都有至少一个公有方法做为外部代码访问其的接口。而抽象方法就是为了方便继承而引入的,我们先来看一下抽象类和抽象方法的定义再说明它的用途。

什么是抽象方法?我们在类里面定义的没有方法体的方法就是抽象方法,所谓的没有方法体指的是,在方法声明的时候没有大括号以及其中的内容,而是直接在声明时在方法名后加上分号结束,另外在声明抽象方法时还要加一个关键字“abstract”来修饰;

如:

abstract function fun1();
abstract function fun2();

上例是就是“abstract”修饰的没有方法体的抽象方法“fun1()”和“fun2()”,不要忘记抽象方法后面还要有一个分号;那么什么是抽象类呢?只要一个类里面有一个方法是抽象方法,那么这个类就要定义为抽象类,抽象类也要使用“abstract”关键字来修饰;在抽象类里面可以有不是抽象的方法和成员属性,但只要有一个方法是抽象的方法,这个类就必须声明为抽象类,使用”abstract”来修饰。

abstract class Demo {
    var $test;
 
    abstract function fun1();
    abstract function fun2();
 
    function fun3() {
        ...
    }

上例中定义了一个抽象类“Demo”使用了”abstract”来修饰, 在这个类里面定义了一个成员属性“$test”,和两个抽象方法“fun1”和“fun2”,还有一个非抽象的方法fun3();那么抽象类我们怎么使用呢?最重要的一点就是抽象类不能产生实例对象, 所以也不能直接使用,前面我们多次提到过类不能直接使用,我们使用的是通过类实例化出来的对象,那么抽象类不能产生实例对象我们声明抽象类有什么用呢?我们是将抽象方法是做为子类重载的模板使用的,定义抽象类就相当于定义了一种规范,这种规范要求子类去遵守,子类继承抽象类之后,把抽象类里面的抽象方法按 照子类的需要实现。子类必须把父类中的抽象方法全部都实现,否则子类中还存在抽象方法,那么子类还是抽象类,还是不能实例化类;为什么我们非要从抽象类中继承呢?因为有的时候我们要实现一些功能就必须从抽象类中继承,否则这些功能你就实现不了,如果继承了抽象类,就要实现类其中的抽象方法;

<?
abstract class Demo {
    var $test;
 
    abstract function fun1();
    abstract function fun2();
 
    function fun3() {
        ...
    }
}
 
$demo = new Demo(); // 抽象类不能产生实例对象,所以这样做是错的,实例化对象交给子类
 
class Test extends Demo {
    function fun1() {
        ...
    }
 
    function fun2() {
        ...
    }
}
 
$test = new Test(); // 子类可以实例化对象,因为实现了父类中所有抽象方法
?>

 

>> 阅读全文  >>

PHP OOP思想之__克隆对象__call()处理调用错误

By heiry on 2009-10-21 [ in 技术 ]

在程序开发中,如果在使用对象调用对象内部方法时候,调用的这个方法不存在那么程序就会出错,然后程序退出不能继续执行。那么可不可以在程序调用对象内部 不存在的方法时,提示我们调用的方法及使用的参数不存在,但程序还可以继续执行,这个时候我们就要使用在调用不存在的方法时自动调用的方 法“__call()”。

<?php
// 这是一个测试的类,里面没有属性和方法
class Test {
}
 
// 产生一个Test类的对象
$test = new Test();
 
// 调用对象里不存在的方法
$test->demo("one", "two", "three");
 
// 程序不会执行到这里
echo "this is a test<br>";
?>

上例出现如下错误,程序通出不能继续执行;

Fatal error: Call to undefined method Test::demo()

下面我们加上“__call()”方法,这个方法有2个参数,第一个参数为调用不存在的方法过程中,自动调用__call()方法时,把这个不存在的方法的方法名传给第一个参数,第二个参数则是把这个方法的多个参数以数组的形式传进来

<?php
// 这是一个测试的类,里面没有属性和方法
class Test {
    // 调用不存的方法时自动调用的方法,第一个参数为方法名,第二个参数是数组参数
    function __call($function_name, $args) {
        print "你所调用的函数:$function_name(参数:";
        print_r($args);
        echo ")不存在!<br>";
    }
}
 
// 产生一个Test类的对象
$test = new Test();
 
// 调用对象里不存在的方法
$test->demo("one", "two", "three");
 
// 程序不会退出可以执行到这里
echo "this is a test<br>";
?>

上例输出结果为:

你所调用的函数: demo(参数:Array ( [0] => one [1] => two [2] => three ) )不存在!
this is a test

 

>> 阅读全文  >>

PHP OOP思想之__克隆对象__clone()方法

By heiry on 2009-10-21 [ in 技术 ]

有的时候我们需要在一个项目里面,使用两个或多个一样的对象,如果你使用“new”关键字重新创建对象的话,再赋值上相同的属性,这样做比较烦琐而且也容易出错,所以要根据一个对象完全克隆出一个一模一样的对象,是非常有必要的,而且克隆以后,两个对象互不干扰。

在PHP4中我们使用“clone”这个关键字克隆对象;

<?
class Person {
    // 下面是人的成员属性
    var $name;  // 人的名子
    var $sex;   // 人的性别
    var $age;   // 人的年龄
 
    // 定义一个构造方法参数为属性姓名$name、性别$sex和年龄$age进行赋值
    function __construct($name = "", $sex = "", $age = "") {
        $this->name = $name;
        $this->sex = $sex;
        $this->age = $age;
    }
 
    // 这个人可以说话的方法,说出自己的属性
    function say() {
        echo "我的名子叫:" . $this->name . " 性别:" . $this->sex . " 我的年龄是:" . $this->age . "<br>";
    }
}
 
$p1 = new Person("张三", "男", 20);
 
// 使用“clone”克隆新对象p2,和p1对象具有相同的属性和方法。
$p2 = clone $p1;
$p2->say();
?>

PHP4定义了一个特殊的方法名“__clone()”方法,是在对象克隆时自动调用的方法,用“__clone()”方法将建立一个与原对象拥有相同属 性和方法的对象,如果想在克隆后改变原对象的内容,需要在__clone()中重写原本的属性和方法,  “__clone()”方法可以没有参数,它自 动包含$this和$that两个指针,$this指向复本,而$that指向原本

<?
class Person {
    // 下面是人的成员属性
    var $name;  // 人的名子
    var $sex;   // 人的性别
    var $age;   // 人的年龄
 
    // 定义一个构造方法参数为属性姓名$name、性别$sex和年龄$age进行赋值
    function __construct($name = "", $sex = "", $age = "") {
        $this->name = $name;
        $this->sex = $sex;
        $this->age = $age;
    }
 
    // 这个人可以说话的方法, 说出自己的属性
    function say() {
        echo "我的名子叫:" . $this->name . " 性别:" . $this->sex . " 我的年龄是:" . $this->age . "<br>";
    }
 
    // 对象克隆时自动调用的方法, 如果想在克隆后改变原对象的内容,需要在__clone()中重写原本的属性和方法
    function __clone() {
        // $this指的复本p2, 而$that是指向原本p1,这样就在本方法里,改变了复本的属性。
        $this->name = "我是假的 $that->name";
        $this->age = 30;
    }
}
 
$p1 = new Person("张三", "男", 20);
$p2 = clone $p1;
$p1->say();
$p2->say();
?>

上例输出:

我的名子叫:张三 性别:男 我的年龄是:20
我的名子叫:我是假的张三 性别:男 我的年龄是:30

>> 阅读全文  >>

PHP OOP思想之__toString()方法

By heiry on 2009-10-21 [ in 技术 ]

我们前面说过在类里面声明“__”开始的方法名的方法(PHP给我们提供的),都是在某一时刻不同情况下自动调用执行的方 法,“__toString()”方法也是一样自动被调用的,是在直接输出对象引用时自动调用的, 前面我们讲过对象引用是一个指针,比如 说:“$p=new Person()“中,$p就是一个引用,我们不能使用echo 直接输出$p,这样会输 出“Catchable fatal error: Object of class Person could not be converted to string”这样的错误,如果你在类里面定义了“__toString()”方法,在直接输出对象引用的时候,就不会产生错误,而是自动调用 了”__toString()”方法, 输出“__toString()”方法中返回的字符,所以“__toString()”方法一定要有个返回值(return 语句)

<?php
// Declare a simple class
class TestClass {
    public $foo;
 
    public function __construct($foo) {
        $this->foo = $foo;
    }
 
    // 定义一个__toString方法,返加一个成员属性$foo
    public function __toString() {
        return $this->foo;
    }
}
 
$class = new TestClass('Hello');
 
// 直接输出对象
echo $class;
?>

上例输出:Hello

>> 阅读全文  >>

PHP几个函数技巧

By heiry on 2009-10-21 [ in 技术 ]

HP的一些小技巧,比较基础,总结一下,老鸟换个姿势飘过去就是。

1. str_replace

str_replace是非常常常常常用的php函数,用于字符串替换,经常看到某些php新人为了替换一批字符串,写了好多行str_replace,实在是惨不忍睹。

比如这个例子:

$str = '某人的栖息地 --- blog.snsgou.com';
$str = str_replace('某人', '坏人', $str);
$str = str_replace('的', 'di', $str);
$str = str_replace('栖息地', '猪窝窝', $str);
$str = str_replace('blog.snsgou.com', 'snsgou.com', $str);

以上,替换了4次字符串,实际只要换个写法,一行就搞定了:

$str = '某人的栖息地 --- blog.snsgou.com';
$str = str_replace(array('某人', '的', '栖息地', 'blog.snsgou.com'), array('坏人', 'di', '猪窝窝', 'snsgou.com'), $str);

2. array

经常看到有人拿数组这样写:

echo $arr[some_key];

上面这行代码能跑,看上去也没什么大问题,但是如果你把php.ini的error notice打开的话,会收到一大批error。php解析器首先是拿“some_key”当作一个常量来解释的,但如果没有定义some_key这样一 个常量,解析器还是很宽容的把它当作了一个字符串来看待。因此新人同学们最好写完整一点:

  
echo "这是混在双引号中的字符串{$arr['some_key']}";

3. 类型戏法

类型戏法相当好用,比如有一个表单提交过来的变量,正常情况下它应该是整型的,有时候偷懒省去校验的写法可以是这样的:

$intVar = (int)$_POST['post_var'];

再比如数组,有时候写键值要打引号是不是很不爽啊,我们可以把它转换成object,比如:

$arr = array('name' => 'volcano', 'sex' => 'male');
$arr = (object)$arr;
 
echo $arr->name;
echo $arr->sex;

是不是很省事?

4. lambda函数

lamda函数和array_*系列函数使用有奇效,拿php手册上的一个例子来说:

<?php
    $av = array("the ", "a ", "that ", "this ");
    array_walk($av, create_function('&$v,$k', '$v = $v . "mango";'));
    print_r($av);
?>

至少省了一个for循环

5. 嵌套循环显示表格的单元格

嵌套循环显示表格的单元格,这是一个很老的话题哦,往往会要在某个单元格后边加个条件判断什么的,考虑是不是要输出tr抑或是td标签。

俺这里介绍一个办法,利用array_chunk函数能够比较工整的输出html,见下例,这个例子要输出一个4行6列的表格:

<?php
$arr = range(1, 24); //这个会生成一个数组array(1,2,3,4....24)
$arr = array_chunk($arr, 6);
 
// output table
?>
 
<table>
    <?php foreach($arr as $row): ?>
    <tr>
        <?php foreach($row as $col):?>
        <td><?php echo $col?></td>
        <?php endforeach;?>
    </tr>
    <?php endforeach;?>
</table>

文章来源:http://www.cnblogs.com/52php/p/5657866.html

>> 阅读全文  >>

PHP OOP思想之final、static、const

By heiry on 2009-10-21 [ in 技术 ]

一.final

这个关键字只能用来定义和定义方法, 不能使用final这个关键字来定义成员属性,因为final是常量的意思,我们在PHP里定义常量使用的是define()函数,所以不能使用final来定义成员属性。

使用final关键标记的类不能被继承;

<?php
final class Person {
    function say() {
 
    }
}
 
class Student extends Person {
    function say() {
 
    }
}
?>

会出现下面错误:

Fatal error: Class Student may not inherit from final class (Person)

 

使用final关键标记的方法不能被子类覆盖,是最终版本;

<?php
class Person {
    final function say() {
 
    }
 
}
 
class Student extends Person {
    function say() {
 
    }
}
?>

会出现下面错误:

会出现下面错误:

Fatal error: Cannot override final method Person::say()

 

(更多…)

>> 阅读全文  >>

PHP OOP思想之访问控制类型(public,protected,private)

By heiry on 2009-10-21 [ in 技术 ]

类型的访问修饰符允许开发人员对类成员的访问进行限制,这是PHP5的新特性,但却是OOP语言的一个好的特性。而且大多数OOP语言都已支持此特性。PHP5支持如下3种访问修饰符:

public (公有的、默认的),protected (受保护的)和private (私有的)三种。

public 公有修饰符,类中的成员将没有访问限制,所有的外部成员都可以访问(读和写)这个类成员(包括成员属性和成员方法),在PHP5之前的所有版本中,PHP 中类的成员都是public的,而且在PHP5中如果类的成员没有指定成员访问修饰符,将被视为public 。例:

public $name;
public function say(){ };

private 私有修改符,被定义为private的成员,对于同一个类里的所有成员是可见的,即没有访问限制;但对于该类的外部代码是不允许改变甚至读操作,对于该类的子类,也不能访问private修饰的成员。例:

private $var1 = 'A';            // 属性
private function getValue(){ }  // 函数

类内部访问方式为:$this->var1,$this->getValue()
protected保护成员修饰符,被修饰为protected的成员不能被该类的外部代码访问。但是对于该类的子类有访问权限,可以进行属性、方法的读及写操作,该子类的外部代码包括其的子类都不具有访问其属性和方法的权限。

private protected public
同一个类中
类的子类中
所有的外部成员

属性访问控制示例:

<?php
/**
 * Define MyClass
 */
class MyClass {
    public $public = 'Public';
    protected $protected = 'Protected';
    private $private = 'Private';
 
    function printHello() {
        echo $this->public;
        echo $this->protected;
        echo $this->private;
    }
}
 
$obj = new MyClass();
echo $obj->public;       // Works
echo $obj->protected;    // Fatal Error
echo $obj->private;      // Fatal Error
$obj->printHello();      // Shows Public, Protected and Private
 
/**
 * Define MyClass2
 */
class MyClass2 extends MyClass {
    // We can redeclare the public and protected method, but not private
    protected $protected = 'Protected2';
 
    function printHello() {
        echo $this->public;
        echo $this->protected;
        echo $this->private;
    }
}
 
$obj2 = new MyClass2();
echo $obj->public;       // Works
echo $obj2->private; // Undefined
echo $obj2->protected;   // Fatal Error
$obj2->printHello(); // Shows Public, Protected2, not Private

方法访问控制示例:

<?php
/**
 * Define MyClass
 */
class MyClass {
    // Contructors must be public
    public function __construct() { }
 
    // Declare a public method
    public function MyPublic() { }
 
    // Declare a protected method
    protected function MyProtected() { }
 
    // Declare a private method
    private function MyPrivate() { }
 
    // This is public
    function Foo() {
        $this->MyPublic();
        $this->MyProtected();
        $this->MyPrivate();
    }
}
 
$myclass = new MyClass;
$myclass->MyPublic();        // Works
$myclass->MyProtected(); // Fatal Error
$myclass->MyPrivate();       // Fatal Error
$myclass->Foo();         // Public, Protected and Private work
 
/**
 * Define MyClass2
 */
class MyClass2 extends MyClass {
    // This is public
    function Foo2() {
        $this->MyPublic();
        $this->MyProtected();
        $this->MyPrivate();      // Fatal Error
    }
}
 
$myclass2 = new MyClass2;
$myclass2->MyPublic();   // Works
$myclass2->Foo2();       // Public and Protected work, not Private

另外在子类覆盖父类的方法时也要注意一点,子类中方法的访问权限一定不能低于父类被覆盖方法的访问权限,也就是一定要高于或等于父类方法的访问权限。

例如,如果父类方法的访问权限是protected,那么子类中要覆盖的权限就要是protected和public,如果父类的方法是public那么子类中要覆盖的方法只能也是public,总之子类中的方法总是要高于或等于父类被覆盖方法的访问权限。

>> 阅读全文  >>


© 2009-2021 MOSANG.NET DESIGNED BY HEIRY