PHP面向对象

客官°小女子只卖身不卖艺 2022-06-05 07:23 380阅读 0赞

最近在重新学习PHP核心内容,这里是关于面向对象的有关内容.关于面向对象的基本概念这里不做解释.主要学习php面向对象与java的区别.

PHP类的基本形式:
学过Java的很容易理解,这里不详细解释

  1. <?php class Car{ public $name = "carname"; public function __construct(){ //构造函数 dosomething; } public function getName(){ echo $this->name; } }

不过跟java不同的是,php是不支持重载的,起码目前来说是,也就是不能像java那样,存在方法名相同,参数列表不相同的方法.

  1. <?php class Car{ public $name = "carname"; public function __construct(){ //构造函数 dosomething; } /* public function __construct(){ //构造函数2 dosomething; //这是不允许的 } */ public function getName(){ echo $this->name; } }

那么我要满足java中重载的效果该怎么办?利用php的内置函数来模拟就可以了:
func_num_args() 函数是获取传递该方法的参数个数
func_get_arg(index) 获取第i个参数,从0开始

  1. public function __construct(){
  2. $args_num = func_num_args();
  3. switch ($args_num)
  4. {
  5. case 0 :
  6. echo "初始化了一个无参car类对象<br>";
  7. break;
  8. case 1 :
  9. //获取第一个变量
  10. $carname = func_get_arg(0);
  11. $this->name = $carname;
  12. echo "初始化了一个名为".$carname."的car类对象<br>";
  13. break;
  14. default :
  15. exit ("找不到对应的构造方法");
  16. }
  17. }

同时PHP还有一种构造方法的表示方式:

  1. public function Car(){
  2. //dosomething;
  3. echo "我才是构造方法";
  4. }

与类名同名的表示方法,跟java类似,同样的他也不支持重载.那么现在有个问题如果同时存在两种表达形式,哪个会生效?我们实验一下.

  1. <?php
  2. require 'car.php';
  3. $car = new Car();
  4. $car2 = new Car('奥迪A6');
  5. // $car3 = new Car("东风本田",'10w');
  6. //程序退出
  7. $car->getName();
  8. $car2->getName();
  9. // $car3->getName();

输出结果:

初始化了一个无参car类对象
初始化了一个名为奥迪A6的car类对象
carname奥迪A6

也就是说,是__construct函数起作用.总结起来

1.一个类中如果同时存在__construct(非父类的)和与类名同名函数,则__construct是构造函数,而同名函数则当作普通函数;

同时,如果不写构造方法,PHP会隐形地调用无参构造方法,这一点跟java类似.

那么我们还知道java存在一个构造函数链的问题,由于篇幅的问题,java构造函数链问题可以去看看这篇文章:Java杂谈之构造函数链

总得来说有几点

  1. 在继承关系中,子类必须显性或隐形地调用父类的构造方法
  2. 如果子类调用显式调用父类的构造方法(有参的),但是父类不存在这样的构造方法会报错
  3. 构造方法可以调用自身的重载构造方法
  4. 显式调用必须在第一行

那么我们来模拟以下看看PHP继承关系中构造链的具体情况

  1. <?php class Person{ public $name ="未初始化的父类名"; public function __construct(){ $this->name = "初始化后父类名"; echo "这个是父类"; } } class Employee extends Person{ public $salary; public function __construct(){ echo "这个是子类<br>"; } } $emp = new Employee(); echo $emp->name;

以上代码输出是 :

这个是子类
未初始化的父类名

子类继承了父类的属性,但是没有调用构造方法.也就是说,PHP并不会自动的调用父类的构造方法.但是可以显式调用,同时,即使父类中的构造方法无带参,还是可以传递参数.
当然了,如果不用内置函数去获取传递的参数,其实是获取不了参数的,但是正如前文说到,PHP没有java中的重载功能,但是用func_get_args()等方法来实现还是可以的.

  1. <?php class Person{ public $name ="未初始化的父类名"; public function __construct(){ $this->name = "初始化后父类名"; echo func_num_args(),PHP_EOL; var_dump (func_get_args()); echo "这个是父类<br>"; } } class Employee extends Person{ public $salary; public function __construct(){ //parent::__construct(); parent::__construct("sdsd",3); echo "这个是子类<br>"; //parent::__construct("sdsd",3);不是必须放到函数的第一行 } } $emp = new Employee(); echo $emp->name; //输出效果: /* 2 /var/www/html/test/person.php:8: array (size=2) 0 => string 'sdsd' (length=4) 1 => int 3 这个是父类 这个是子类 初始化后父类名 */

同样地,调用父类的其他成员方法用parent::function()的方式调用

下面我们讲讲PHP独特的魔术方法,其实就是一些语法糖,其实上文提到的__construct已经是一个魔术方法,在php的定义中,魔术方法是以 两个下划线开头的,具有特殊作用的方法.与__construct 方法对应的是__destruct方法,复制在某个对象所有引用都被删除,或则对象被显式销毁时执行.
下面说说__set和__get

  1. <?php class Aclass{ private $user = 1; private $pwd = 2; } $a = new Aclass(); echo $a->user; echo $a->pwd; $a->name = 9; echo $a->name; echo $a->big;

以上这段代码会报错,其实就是不可访问私有属性,用__set __get 可以完美解决,其实这里涉及到了面向对象的封装思想.不详细解释,与java类比就是各个属性的setter和getter,某种程度上说比java的更好用

  1. <?php class Aclass{ private $user = 1; private $pwd = 2; public function __set($name,$value){ $this->$name=$value; } public function __get($name){ if(!isset($this->$name)) { echo $name." is not define<br>"; $this->$name="default value<br>";//定义属性并初始值 } return $this->$name; } } $a = new Aclass(); echo $a->user; echo $a->pwd; $a->name = 9; echo $a->name; echo $a->big; //输出结果: /* 129big is not define default value */

接下来还有一个比较常用的魔术方法__call和__callStatic
为了预防调用不存在的方法而出错,或者出于程序简洁的原因,使用__call魔术方法可以很好解决

  1. public function __call($name,$args){
  2. echo "这里实现函数逻辑";
  3. }
  4. $a->test();//输出:这里实现函数逻辑

看着很鸡肋?其实很多PHP的MVC框架设计中是很有用的语法,他使方法的动态创建变为可能.
下面一段代码摘录与<< PHP核心技术与最佳实践>>一书,以下代码实现了一个简易的ORM模型

  1. <?php abstract class ActiveRecord{ protected static $table;//存放表名 protected $fieldvalues;//一个数组,存放各种数据 public $select;//一个sql语句 static function findById($id) { //构造sql语句 $query = "select * from ". static::$table. " where id = $id"; return self::createDomain($query); } function __get($fieldname) { return $this->fieldvalues[$fieldname]; } //当调用不存在的静态方法时会调用该方法,参数1是不存在的静态方法的方法名,参数2是欲传递的参数列表 static function __callStatic($method,$args){ $field = preg_replace('/^findBy(\w*)$/','${1}',$method);//把检索字段提炼出来 $query = "select * from ".static::$table." where $field = '$args[0]'";//组合成新的sql语句 return self::createDomain($query); } //对象的创建,数据表的初始化,返回一个对象 private static function createDomain($query) { $klass = get_called_class();//获取调用类的类信息 $domain = new $klass();//动态创建一个类 $domain -> fieldvalues = array();//初始化数组 $domain -> select = $query;//把之前创建的sql语句存起来 //结构化数组 foreach($klass::$fields as $field => $type) { $domain->fieldvalues[$field] = 'TODO:set from sql result'; } return $domain; } } class Customer extends ActiveRecord{ protected static $table = 'custdb'; protected static $fields = array( 'id' =>'int', 'email' => 'varchar', 'lastname'=>'varchar' ); } class Sales extends ActiveRecord{ protected static $table = 'salesdb'; protected static $fields = array( 'id' =>'int', 'item' => 'varchar', 'qty'=>'int' ); } $rest = assert("select * from custdb where id=123" == Customer::findById(123)->select); var_dump($rest);//true $cus = Customer::findById(123); var_dump($cus); var_dump($cus->email); $cus2 = Customer::findByLastName('ben');//该静态方法不存在,自动调用魔术方法__callStatic var_dump($cus2);

接下来是__toString,这个魔术方法其实就是从java中收到的启发,一般echo后不可直接跟一个对象的,无法输出,但是只要实现了toString的魔术方法,echo也可以直接输出一个对象.这里跟java中所有对象都实现了tostring方法一样.都是可以自定义的.

面向对象中还有一个常见的问题,就是多态
区别多态的关键在于看对象是否属于同一类型,如果同一个类型调用相同函数返回不同的结果,那么他就是多态的,否则不能称其为多态.

在java中的多态跟PHP的”多态”是不一样的,在java中,子类对象可以向上转型为父类对象,这些对象都是同一类对象.但是PHP是没有对象转型机制的,不能像java那样,实现派生类对象赋值给基类对象,然后调用时动态改变指向.在PHP中对象都是确定的,是不同类的对象.

但是PHP中是又接口的,有接口可以实现多态,下面给出一个例子

  1. <?php interface employee{ public function working(); } class Teacher implements employee{ public function working(){ echo "teaching"; } } class student implements employee{ public function working(){ echo "studying"; } } class coder implements employee{ public function working(){ echo "coding"; } } function myjob(employee $e){ $e->working(); } $a = new Teacher(); $b = new student(); $c = new coder(); myjob($a); myjob($b); myjob($c); //输出 teachingstudyingcoding

符合”同一类型,不同结果”,所以以上可以说PHP具有多态性.

发表评论

表情:
评论列表 (有 0 条评论,380人围观)

还没有评论,来说两句吧...

相关阅读

    相关 php面向对象

       js面向对象      类:具有相同特征的一些对象的集合;     对象:具体某一个事物了,都可以叫对象;     类:通过function定义的类,所以js里类的

    相关 面向对象PHP(四)

    <?php / 接口就是把不同类的共同行为进行了定义,然后在不同的类里面实现不同的功能。 因为接口的方法实现可以有很多,所以对于接口里面定义的方法的具体实现是多种多

    相关 面向对象PHP(二)

    <?php / 1.子类与父类方法相同可以对父类方法重写 2.如果不希望父类被重写,用final关键字修饰,可以修饰类中方法,也可以是一个类(该类所有方法均不能被重

    相关 php面向对象

    近一段时间有一种学习的强烈欲望,出现了经济危机啊。现在的工资连最基本的生活都不能保证啊,想尽快的摆脱现在的这种局面。 昨天晚上把PHP的面向对象编程的一些最基本的概念看了看。