当前位置: 澳门新濠3559 > 编程 > 正文

可以在类中、子类中、类外访问,被定义为受保

时间:2019-12-08 22:39来源:编程
访问控制 public(公开的):可以在类中、子类中、类外访问。 protected(受保护的):只能在类本身及子类中访问。 private(私有的):只能在声明他们的类中进行访问,私有的类成员不

访问控制

  public(公开的):可以在类中、子类中、类外访问。

  protected(受保护的):只能在类本身及子类中访问。

  private(私有的):只能在声明他们的类中进行访问,私有的类成员不能被子类或者这个类的对象实例直接访问。

 

一:封装 

传统的JavaScript程序使用函数和基于原型的继承来创建可重用的组件,但是我们更习惯于使用面向对象的方式来开发。ES6已经可以使用class关键字进行面向对象的方式开发了,使用TypeScript不管要编译到哪个ES规范版本的JavaScript,都可以使用class等一系列关键字来进行面向对象的方式开发,功能更强大。

抽象类和方法

  在继承概念被应用在一些场景中,创建一个父类的实例将会显得不怎么合适。在这种情况下,如果将父类定义为一个抽象基类,而不是标准的基类,会显得更加合适(抽象类不能被实例化)。

  抽象类定义了这个基类的继承类(子类)中的一些方法。然后子类会负责定义这些方法的真正的实现。

  抽象类和普通类的区别在于,如果试图从抽象类创建一个对象将会出现一个致命错误,抽象类就是被用来扩展的,然后我们就可以创建这些派生类的实例。

      封装就是把对象中的成员属性和成员方法加上访问修饰符( public(公有),protected(受保护)或 private(私有)),使其尽可能隐藏对象的内部细节,以达到对成员的访问控制

// 类
class FirstClass {
    msg: string;
    //构造函数
    constructor(msg: string) {
        this.msg = msg;
    }
    Show() {
        console.log('Hello ' + this.msg);
    }
}
let first = new FirstClass('world');
first.Show();
// 输出
// Hello world

class 关键字定义一个类。
constructor 定义一个构造函数。一个构造函数就是你用 new 关键字创建一个类的实例时会调用的方法。

  抽象类和方法的定义:

//抽象类的定义从abstract关键字开始
abstract class People{
    protected $name = "";

    //抽象方法以abstract开始,并且抽象方法没有方法体,以分号结束
    abstract public function setName($name);

}

//子类中实现抽象类的方法
class Teacher extends People{

    public function setName($name){
        $this->name = $name;
    }
}

  注意:

  1.在子类里实现抽象方法的时候,其可见性必须高于或等于抽象方法的定义的可见性。如果抽象方法是公开的(public),子类里的实现方法也必须是公开的。如果抽象方法是受保护的(protected),那么子类将只能是受保护的或者公开的。

  2.我们不能将抽象方法定义为私有的(private),因为一个私有的方法不能够被继承。

  3.在所有情况下,方法的实现版本也必须和抽象方法具有一样数目的参数(函数签名要一致)。

  4.子类中必须实现基类中所有的抽象方法,否则将会出现一个致命错误。

  5.属性没有抽象一说,抽象类中的属性定义为正常属性,子类也可以覆盖抽象类中的属性,此时属性的可见性设置与抽象方法是一致的(见第1条)。

 

  本章博客会不定期更新所有有关PHP面向对象的知识,敬请期待……

 

  被定义为公有的类成员可以在任何地方被访问。被定义为受保护的类成员则可以被其自身以及其子类和父类访问。被定义为私有的类成员则只能被其定义所在的类访问(即子类和父类都不可以访问)

继承

面向对象的三个要素是封装继承多态。封装已经体现在类的定义中了,通过继承可以扩展一个类的功能,也可以体现多态这一特性。

class A {
    a: string;
    constructor(a: string) {
        this.a = a;
    }
    show() {
        console.log(this.a + ' from A')
    }
}

class B extends A {
    b: string;
    constructor(a: string, b: string) {
        super(a);//调用父类构造函数
        this.b = b;
    }
    show() {
        console.log(this.a + ' from B ');
    }
}
let a: A = new A('a');
a.show();//a from A
let b: B = new B('a', 'b');
b.show();//a from B
let c: A = new B('c', 'b');
c.show();//c from B
//console.log(c.b);//错误,无法访问派生类的属性
  • 继承使用关键字extends可以在类中、子类中、类外访问,被定义为受保护的类成员则可以被其自身以及其子类和父类访问。。B 继承 A ,则称A是父类,B 是子类。
  • 父类中有构造函数,则子类的构造函数必须调用父类的构造函数。使用关键字 super 调用父类的构造函数,这个函数在子类构造函数中必须放到最开始的地方。
  • 用父类的类型实例化一个子类会导致访问不到子类的属性。let c: A = new B('c', 'b'); 这里对象 c 没法访问子类中定义的属性 b
  • 面向对象中的 继承 强调的是子类与父类的相似性(从父类继承过来的属性与方法)以及扩展父类。而 多态 强调的是子类的不同形态,即跟父类不同的部分。

  类属性必须定义为公有,受保护,私有之一。如果用 var 定义,则被视为公有

公共,私有与受保护的修饰符

public 表示公共的,外部可以访问的。如果不写修饰符,则默认是public。
private 表示私有的,只有内部可以访问的。
protected 表示受保护的,只有类与其子类中可以访问。

class Animal {
    name: string
    protected readonly weight: number;
    private cry: boolean;
    protected constructor(name: string, weight: number) {
        this.name = name;
        this.weight = weight;
        this.cry = true;
    }
    show() {
        console.log(`${this.name} ${this.weight}, 
            can cry ${this.cry}`);
    }
}

class Dog extends Animal {
    constructor(name: string, weight: number) {
        super(name, weight);
    }
    run() {
        //cry是基类的private属性,子类无法访问
        //console.log(`${this.name} ${this.weight}, 
        //    can cry ${this.cry}`);
        console.log(`${this.name} ${this.weight}, 
            I can run`);
    }
}

class Bird1 extends Animal {
    constructor(name: string, weight: number) {
        super(name, weight);
    }
    fly() {
        console.log(`${this.name} ${this.weight}, 
            I can fly`);
    }
}
let dog = new Dog('Dog', 123);
//console.log(dog.weight);//错误,外部无法访问protected定义的属性
dog.run();
//输出
/*
Dog 123, 
I can run
*/
let bird = new Bird1('Bird1', 11.3);
bird.fly();
//输出
/*
Bird1 11.3, 
            I can fly
*/
dog.show();
bird.show();
//输出
/*
Dog 123, 
            can cry true
Bird1 11.3, 
            can cry true
*/
  • 父类中 publicprotected 的属性与方法在子类中都可以访问, private 定义的属性与方法无法访问(父类的 cry 属性子类无法访问)。在类的外部只能访问 public 定义的属性与方法(protected 属性无法访问)。
  • 父类的构造函数定义成 protected ,则无法使用这个父类实例化一个对象。
class Bird2 {
    name: string
    protected readonly weight: number;
    private cry: boolean;
    constructor(name: string, weight: number) {
        this.name = name;
        this.weight = weight;
        this.cry = true;
    }
    show() {
        console.log(`${this.name} ${this.weight}, 
            can cry ${this.cry}`);
    }

    fly() {
        console.log(`${this.name} ${this.weight}, 
            I can fly`);
    }
}
let bird2 = new Bird2('Bird2', 13.1);
//bird = bird2;//错误,不是从同一个基类派生,类型不兼容

Bird2Bird1 拥有相同的属性与方法,不同的是 Bird1 是通过继承获得了一部分,而Bird2 是全部自己定义的。这两个类是不兼容的。如果想要类型兼容,除了要有相同的属性定义,还必须都是来自同一处声明时,才认为这两个类型是兼容的,也就是继承与同一个父类或实现了同一个接口。

澳门新濠3559 1

参数属性

class Demo {
    constructor(private name: string) {
        console.log(this.name);
    }
}
let demo = new Demo('Demo');//Demo

代码中并没有定义一个 name 属性,但是在构造函数中却可以访问,这是因为在构造函数中使用了参数属性,private name: string 来创建和初始化 name 属性。

<?php
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; // 这行能被正常执行
echo $obj->protected; // 这行会产生一个致命错误
echo $obj->private; // 这行也会产生一个致命错误
$obj->printHello(); // 输出 Public、Protected 和 Private

class MyClass2 extends MyClass
{
    // 可以对 public 和 protected 进行重定义,但 private 而不能
    protected $protected = 'Protected2';
    function printHello()
    {
        echo $this->public;
        echo $this->protected;
        echo $this->private;
    }
}
$obj2 = new MyClass2();
echo $obj2->public; // 这行能被正常执行
echo $obj2->private; // 未定义 private
echo $obj2->protected; // 这行会产生一个致命错误
$obj2->printHello(); // 输出 Public、Protected2 和 Undefined
?>

存取器

如果想访问类中 protectedprivate 定义的属性要怎么办?

class Demo1 {
    private _name: string;
    get name(): string {
        return this._name;
    }
    set name(name: string) {
        this._name = name;
    }
}
let demo1 = new Demo1();
demo1.name = 'Demo1';
console.log(demo1.name);//Demo1
  • 为了不破坏封装性,有些属性必须定义成 protectedprivate,但是在类的外部又需要调整这个属性,这就要用到get和 set来访问了。
  • get提供给外部访问属性的权限。
  • set提供给外部修改属性的权限。

澳门新濠3559 2

静态属性

class Add {
    static num: number = 19;
    static show() {
        console.log(Add.num);
    }
    show() {
        console.log(Add.num);
    }
}
console.log(Add.num);//19
Add.show();//19
let add1 = new Add();
let add2 = new Add();
Add.num++;
add1.show();//20
add2.show();//20
  • 使用关键字 static 定义一个静态的属性或方法。静态属性是不属于任何对象的,必须使用类名加属性名的方式访问(如例子中:Add.show)。
  • 一个类的所有实例共享这个类中定义的静态属性。(例子中给静态属性加1后,所有的实例访问这个属性发现结果是一致的)。

  类中的方法可以被定义为公有,私有或受保护。如果没有设置这些关键字,则该方法默认为公有

抽象类

抽象类是不能实例化的类。关键字 abstract 定义一个抽象类或抽象方法。

abstract class DemoA {
    readonly name: string;
    constructor(name: string) {
        this.name = name;
    }
    abstract show(): void;
}
class DemoB extends DemoA {
    show() {
        console.log(this.name);
    }
}
//错误,不能实例化一个抽象类
//let demoA = new DemoA()
let demoA: DemoA = new DemoB('DemoB');
let demoB: DemoB = new DemoB('DemoB');
demoA.show();//DemoB
demoB.show();//DemoB
  • 抽象类不能用来实例化一个对象。
  • 抽象方法是没有方法体的,子类如果不是抽象类,就必须实现父类中的所有抽象方法。

澳门新濠3559 3

实现接口

TypeScript能够用 interface 来明确的强制一个类去实现某种契约规范。一个类通过关键字 implements 来实现一个接口。

enum Color {Red, Green, Blue};

interface Point {
    readonly x: number;
    readonly y: number;
}

interface Bullet {
    name: string;//子弹名称
    damage: number;//子弹伤害值
    color: Color;//子弹颜色
    speed: number;//子弹速度
    bomb: boolean;//是否炸弹
    aa?: string;
    Shoot(from: Point, to: Point);
}

class Bullet1 implements Bullet {
    constructor(public name: string,
        public damage: number,
        public color: Color,
        public speed: number,
        public bomb: boolean) {

        }
    Shoot(from: Point, to: Point) {
        console.log(`bullet ${this.name}, 
            damage ${this.damage},
            color ${this.color}, 
            is bomb ${this.bomb}, 
            speed ${this.speed},
            shooting from (${from.x}, ${from.y})
            to (${to.x}, ${to.y})`);
    }
}

let bullet = new Bullet1('Bullet1', 11, Color.Blue, 33, false);
bullet.Shoot({x: 10, y: 10}, {x: 100, y: 100});
//输出
/*
bullet Bullet1, 
damage 11,
color 2, 
is bomb false, 
speed 33,
shooting from (10, 10)
to (100, 100)
*/
  • 接口就像是一个规范一样,接口中定义的属性除了可选属性以外,实现这个接口的类必须全部拥有。例子中在构造方法里面使用 参数属性的方式定义的这些属性。
  • 接口中定义的方法,类中必须实现。

幻想的路总是为有信念的人准备着。

<?php
class MyClass
{
    public function __construct() { }
    public function MyPublic() { }
    protected function MyProtected() { }
    private function MyPrivate() { }
    function Foo()
    {
        $this->MyPublic();
        $this->MyProtected();
        $this->MyPrivate();
    }
}
$myclass = new MyClass;
$myclass->MyPublic(); // 这行能被正常执行
$myclass->MyProtected(); // 这行会产生一个致命错误
$myclass->MyPrivate(); // 这行会产生一个致命错误
$myclass->Foo(); // 公有,受保护,私有都可以执行

class MyClass2 extends MyClass
{
    function Foo2()
    {
        $this->MyPublic();
        $this->MyProtected();
        $this->MyPrivate(); // 这行会产生一个致命错误
    }
}
$myclass2 = new MyClass2;
$myclass2->MyPublic(); // 这行能被正常执行
$myclass2->Foo2(); // 公有的和受保护的都可执行,但私有的不行
?>

澳门新濠3559 4

 

二:继承

    类继承:

     一个类可以在声明中用 extends 关键字继承另一个类的方法和属性。PHP不支持多重继承,一个类只能继承一个基类

澳门新濠3559,  被继承的方法和属性可以通过用同样的名字重新声明被覆盖。但是如果父类定义方法时使用了 final,则该方法不可被覆盖

  当覆盖方法时,参数必须保持一致否则 PHP 将发出 E_STRICT 级别的错误信息。但构造函数例外,构造函数可在被覆盖时使用不同的参数

澳门新濠3559 5

<?php
class foo
{
    public function printItem($string) 
    {
        echo 'Foo: ' . $string . PHP_EOL;
    }
    public function printPHP()
    {
        echo 'PHP is great.' . PHP_EOL;
    }
}
class bar extends foo
{
    public function printItem($string)
    {
        echo 'Bar: ' . $string . PHP_EOL;
    }
}

$foo = new foo();
$bar = new bar();
$foo->printItem('baz'); // Output: 'Foo: baz'
$foo->printPHP();       // Output: 'PHP is great' 
$bar->printItem('baz'); // Output: 'Bar: baz'
$bar->printPHP();       // Output: 'PHP is great'
?>

澳门新濠3559 6

  在子类中,使用parent访问父类中的被覆盖的属性和方法

澳门新濠3559 7

<?php
    class Person {                      
        protected $name;            
        protected $sex;                     
        public function __construct($name=“”, $sex=“男”) { }
        public function say(){}   
    }
   class Student extends Person {  
        private $school;            
        public function __construct($name="", $sex="男", $school="") {   
            parent::__construct($name,$sex); 
            $this->school = $school;
        }
        public function say( ) {
            parent::say();     
            echo "在".$this->school."学校上学<br>";
        }   
    }
$student = new Student("张三","男",20, "edu"); 
$student->say(); 

澳门新濠3559 8

 

抽象

  在面向对象语言中,一个类可以有一个或多个子类,而每个类都有至少一个公有方法作为外部代码访问其的接口。而抽象方法就是为了方便继承而引入的

  当类中有一个方法,他没有方法体,也就是没有花括号,直接分号结束,像这种方法我们叫抽象方法,必须使用关键字abstract定义

public abstract function fun();

  包含这种方法的类必须是抽象类也要使用关键字abstract加以声明

  定义为抽象的类不能被实例化。任何一个类,如果它里面至少有一个方法是被声明为抽象的,那么这个类就必须被声明为抽象的。被定义为抽象的方法只是声明了其调用方式(参数),不能定义其具体的功能实现

  抽象方法的作用就是规定了子类必须有这个方法的实现,功能交给子类,只写出结构, 而没有具体实现,实现交给具体的子类按自己的功能去实现;抽象类的作用是要求子类的结构,所以抽象类就是一个规范

  继承一个抽象类的时候,子类必须定义父类中的所有抽象方法;另外,这些方法的访问控制必须和父类中一样(或者更为宽松)。例如某个抽象方法被声明为受保护的,那么子类中实现的方法就应该声明为受保护的或者公有的,而不能定义为私有的。此外方法的调用方式必须匹配,即类型和所需参数数量必须一致。例如,子类定义了一个可选参数,而父类抽象方法的声明里没有,则两者的声明并无冲突

澳门新濠3559 9

<?php
    abstract class Person {
        public $name;
        public $age;
        abstract function say();        
        abstract function eat();
        function run() {
            echo "11111111111111<br>";
        }
        function sleep() {
            echo "2222222222222222<br>";
        }
    }
    class StudentCn extends Person { //抽象函数下的两个抽象方法必须都要有,且规格参数都要一致
        function say() {
            echo "中文<br>";
        }
        function eat() {
            echo "筷子";
        }
    }
    class StudentEn extends Person {
        function say() {
            echo "english<br>";
        }
        function eat() {
            echo "刀叉";
        }
    }
    $s1 = new StudentEn();
    $s1 -> say();//english
    $s1 -> eat();//刀叉
?>

澳门新濠3559 10

接口

  PHP与大多数面向对象编程语言一样,不支持多重继承,也就是说每个类只能继承一个父类。为了解决这个这个问题,PHP引入了接口,接口的思想是指定了一个实现了该接口的类必须实现的一系列函数

  使用接口(interface),可以指定某个类必须实现哪些方法,但不需要定义这些方法的具体内容。接口是通过interface关键字来定义的,就像定义一个标准的类一样,但其中定义所有的方法都是空的

  接口中定义的所有方法都必须是公有,这是接口的特性。要实现一个接口,使用 implements 操作符。类中必须实现接口中定义的所有方法,否则会报一个致命错误。类可以实现多个接口,用逗号来分隔多个接口的名称。接口中也可以定义常量。接口常量和类常量的使用完全相同,但是不能被子类或子接口所覆盖

澳门新濠3559 11

//实现一个接口
<?php
interface iTemplate //它与抽象区别在于接口定义的方法(公有)必须在类中都要写,而抽象必须抽象方法(公有和保护)
{
    public function setVariable($name, $var);
    public function getHtml($template);
}
class Template implements iTemplate //在下面如果少了其中或是没去写接口下的两个函数 setVariable getHtml的话就会报错。
{
    private $vars = array();
    public function setVariable($name, $var)
    {
        $this->vars[$name] = $var;
    }
    public function getHtml($template)
    {
        foreach($this->vars as $name => $value) {
            $template = str_replace('{' . $name . '}', $value, $template);
        }

        return $template;
    }
}
?>

澳门新濠3559 12

澳门新濠3559 13

//常量不能被覆盖
<?php
interface a
{
    const b = 'Interface constant';
}
echo a::b;
// 错误写法,因为常量不能被覆盖。接口常量的概念和类常量是一样的。
class b implements a
{
    const b = 'Class constant';
}
?>

澳门新濠3559 14

澳门新濠3559 15

//继承多个接口
<?php
interface a
{
const aa = 'Interface constant';
    public function foo();
}
interface b
{
    public function bar();
}
interface c extends a, b //接口与接口直接继承用个extend
{
    public function baz(){
    echo a::aa; //得到变量值 c::aa也是可以
    }
}
?>

class tt implenment c{
  //要将所有的接口函数都写进来。<aa不写没事>
}

澳门新濠3559 16

 

多态

  对象的多态性是指在父类中定义的属性或行为被子类继承之后,可以具有不同的数据类型或表现出不同的行为。这使得同一个属性或行为在父类及其各个子类中具有不同的语义。例如:"几何图形"的"绘图"方法,"椭圆"和"多边形"都是"几何图"的子类,其"绘图"方法功能不同

单态

  说到多态,首先要提到单态设计模式,单态模式的主要作用是保证在面向对象编程设计中,一个类只能有一个实例对象存在

澳门新濠3559 17

<?php
    class DB {
        private static $obj = null;          
        private function __construct() {  
            echo "连接数据库成功<br>";
        }   
        public static function getInstance() {   
            if(is_null(self::$obj))                
                self::$obj = new self();           
            return self::$obj;                     
        }
        public function query($sql) {     
            echo $sql;
        }
    }
// 获得DB这个类的 接口,在去调用这个接口的函数query <体现了单态模式:一个类只能有一个面向对象存在>
    $db = DB::getInstance();//得到是DB类一个对象                 
    $db -> query("select * from user");   
?>

澳门新濠3559 18

  多态展现了动态绑定的功能,也称为“同名异式”,多态可以让软件在开发和维护时,达到充分的延伸性

  在php中,多态性就是指方法的重写,一个子类可中可以重新修改父类中的某些方法,使其具有自己的特征。重写要求子类的方法和父类的方法名称相同,这可以通过声明抽象类或是接口来规范

澳门新濠3559 19

<?php
  <体现了多态模式:一个类computer 可以通过抽象类或接口的引用,来实现一个类可以调用多个面向对象存在>
     //好代码
    interface USB {
        const WIDTH = 12;
        const HEIGHT = 3;            
        function load();
        function run();
        function stop();    
    }
    class Cumputer {
        function useUSB(USB $usb) { //这里的传参  可以是引用接口USB的类
            $usb -> load();
            $usb -> run();
            $usb -> stop();        
        }

    }
    class Mouse implements USB{
        function load() {
            echo "加载鼠标成功!<br>";
        }
        function run() {
            echo "运行鼠标功能!<br>";
        }
        function stop() {
            echo "鼠标工作结束!<br>";
        }
    }
    class KeyPress implements USB {
        function load() {
            echo "加载键盘成功!<br>";
        }
        function run() {
            echo "运行键盘成功!<br>";
        }
        function stop() {
            echo "停止键盘使用!<br>";
        }
    }
    class Worker {
        function work() {
            $c = new Cumputer();
            $m = new Mouse;
            $k = new KeyPress;
            $c->useUSB($k); 
            $c->useUSB($m);
        }
    }
    $w = new Worker;
    $w -> work();
?>

接口和抽象的区别
  • 对接口的使用方式是通过关键字implements来实现的,而对于抽象类的操作是使用类继承的关键字exotends实现的,使用时要特别注意。
  • 接口没有数据成员,但是抽象类有数据成员,抽象类可以实现数据的封装。
  • 接口没有构造函数,抽象类可以有构造函数。
  • 接口中的方法都是public类型,而抽象类中的方法可以使用private、protected或public来修饰。
  • 一个类可以同时实现多个接口,但是只能实现一个抽象类。
  •  
  • 相同点:函数体内不能写任何东西,连两个大括号都不能写!!!如:function getName();这样就行了

澳门新濠3559 20

编辑:编程 本文来源:可以在类中、子类中、类外访问,被定义为受保

关键词:

  • 上一篇:没有了
  • 下一篇:没有了