PHP learning notes 10: classes and objects II

PHP learning notes 10: classes and objects II

Source: php.net

Automatic loading

In real projects, we often put class definitions in a separate PHP file. For example, there is a class MyClass, and the corresponding PHP file name may be my_class.cls.php, use require or include to load the corresponding file.

In addition to manually loading files, php also provides a mechanism for automatically loading class files:

<?php
require_once "../../util/class.php";
spl_autoload_register(function ($clsName){
    $fileName = "./".convert_clsname_to_fname($clsName).".cls.php";
    require_once $fileName;
});
$mc = new MyClass;
var_dump($mc);

As shown above, you can use SPL_ autoload_ The register function registers a custom class loader. The specific responsibility of the loader is to load the corresponding class source code file according to the class name.

Convert here_ clsname_ to_ Fname tool function is a function I wrote that can convert hump style class names to underlined styles. There are many lines of code, so we won't show them here. If you are interested, you can go to Github warehouse in this note.

The php interpreter will invoke the registered class loader after loading new MyClass to load the corresponding class files so that you can use the class correctly.

Constructor

The primary purpose of constructors is to initialize class instances when they are created.

By default, the constructor of the subclass will not actively call the constructor of the parent class:

<?php
class Base
{
    public function __construct()
    {
        echo "Base::__construct is called." . PHP_EOL;
    }
}

class Child extends Base
{
    public function __construct()
    {
        echo "Child::__construct is called." . PHP_EOL;
    }
}

$child =  new Child();
// Child::__construct is called.

In order to correctly call the constructor of the parent class, generally:

...
class Child extends Base
{
    public function __construct()
    {
        parent::__construct();
        echo "Child::__construct is called." . PHP_EOL;
    }
}

$child =  new Child();
// Base::__construct is called.
// Child::__construct is called.

If the subclass does not define a constructor, it will inherit the constructor of the parent class:

<?php
class Base
{
    public function __construct()
    {
        echo "Base::__construct is called." . PHP_EOL;
    }
}

class Child extends Base
{
}

$child =  new Child();
// Base::__construct is called.

Unlike other functions, constructors are not restricted by the "function signature compatibility rule", which is well understood because constructors do not involve polymorphism:

<?php
class Base
{
    public function __construct($param)
    {
        echo "Base::__construct is called." . PHP_EOL;
        echo "\$param:{$param}" . PHP_EOL;
    }
}

class Child extends Base
{
    public function __construct()
    {
        parent::__construct('test');
        echo "Child::__construct is called." . PHP_EOL;
    }
}

$child =  new Child();
// Base::__construct is called.
// $param:test
// Child::__construct is called.

In the above example, the constructor of the subclass does not need parameters, and the constructor of the parent class needs one parameter. The subclass is not compatible with the parent class, but this does not affect the execution of the program.

Starting with php8.0.0, constructors can also use named arguments:

class Pointer
{
    private int $x;
    private int $y;
    public function __construct($x, $y)
    {
        $this->x = $x;
        $this->y = $y;
    }
}
$p = new Pointer(y: 2, x: 1);

Attribute promotion

As in the above example, it is very common to initialize the constructor of an attribute with the same name with the passed in parameters. Therefore, php8.0.0 adds a new syntax to directly convert the parameters in the constructor into attributes with the same name:

<?php
class Pointer
{
    public function __construct(private $x, private $y)
    {
    }
    public function __toString()
    {
        return "Pointer(x:{$this->x},y:{$this->y})";
    }
}
$p = new Pointer(y: 2, x: 1);
echo $p . PHP_EOL;
// Pointer(x:1,y:2)

After using the access modifier on the parameter of the constructor, the parameter will be converted to the attribute with the same name of the class. Of course, the parameter itself is still valid. After the conversion, the code inside the constructor will still be executed normally.

Multi structure

php does not support function overloading, so we can only define one__ The construct method is used as the constructor. If we need multiple constructs like those in C + +, we can create instances by defining multiple static methods as "factory methods":

<?php
class Pointer
{
    private function __construct(private $x, private $y)
    {
    }
    public function __toString()
    {
        return "Pointer(x:{$this->x},y:{$this->y})";
    }
    public static function create_from_normal(int $x, int $y): self
    {
        return new self($x, $y);
    }
    public static function create_from_json(string $jsonStr): self
    {
        $arr = json_decode($jsonStr, true);
        return new self($arr['x'], $arr['y']);
    }
    public static function create_from_array(array $arr): self
    {
        return new self($arr['x'], $arr['y']);
    }
}
$p1 = Pointer::create_from_array(['x' => 1, 'y' => 9]);
$p2 = Pointer::create_from_json('{"x":2,"y":6}');
$p3 = Pointer::create_from_normal(5, 10);
echo $p1 . PHP_EOL;
echo $p2 . PHP_EOL;
echo $p3 . PHP_EOL;
// Pointer(x:1,y:9)
// Pointer(x:2,y:6)
// Pointer(x:5,y:10)

The example shows how to create the Pointer class in three ways. If you create a class in this way, you can define the constructor as private or protected, which can avoid inadvertent use of the constructor.

Destructor

Like C + +, php classes also have destructors, which will be called when the object is destroyed:

<?php
class MyClass
{
    public function __destruct()
    {
        echo __CLASS__ . "'s __destruct is called." . PHP_EOL;
    }
}
$mc =  new MyClass;
// MyClass's __destruct is called.

access control

You can use the access modifier public/protected/private to access control the properties, methods and constants of a class.

attribute

The public attribute can be accessed anywhere, the protected attribute can only be accessed in classes and subclasses, and the private attribute can only be accessed in the class to which it belongs:

<?php
class MyClass
{
    public $publicAttr = 'public attr';
    protected $protectedAttr = 'protected attr';
    private $privateAttr = 'private attr';
    public function __construct()
    {
        echo $this->publicAttr . PHP_EOL;
        echo $this->protectedAttr . PHP_EOL;
        echo $this->privateAttr . PHP_EOL;
    }
}
class Child extends MyClass
{
    public function __construct()
    {
        echo $this->publicAttr . PHP_EOL;
        echo $this->protectedAttr . PHP_EOL;
    }
}
$mc = new MyClass;
echo $mc->publicAttr;
// public attr
// protected attr
// private attr
// public attr

The access rules for static attributes are the same as those for normal attributes.

method

The control rules of access qualifiers on methods are similar to properties:

<?php
class MyClass{
    public function __construct()
    {
        $this->public_method();
        $this->protected_method();
        $this->private_method();
    }
    public function public_method(){
        echo "public method is called.".PHP_EOL;
    }
    protected function protected_method(){
        echo "protected method is called.".PHP_EOL;
    }
    private function private_method(){
        echo "private method is called.".PHP_EOL;
    }
}
class Child extends MyClass{
    public function __construct()
    {
        $this->public_method();
        $this->protected_method();
    }
}
$mc = new MyClass;
$mc->public_method();
// public method is called.
// protected method is called.
// private method is called.
// public method is called.

constant

Starting with php7.1.0, class constants can also use the access modifier:

<?php
class MyClass
{
    public const PUBLIC_CONST = 'public const';
    protected const PROTECTED_CONST = 'protected const';
    private const PRIVATE_CONST = 'private const';
    public function __construct()
    {
        echo self::PUBLIC_CONST . PHP_EOL;
        echo self::PROTECTED_CONST . PHP_EOL;
        echo self::PRIVATE_CONST . PHP_EOL;
    }
}
class Child extends MyClass
{
    public function __construct()
    {
        echo parent::PUBLIC_CONST . PHP_EOL;
        echo parent::PROTECTED_CONST . PHP_EOL;
    }
}
echo MyClass::PUBLIC_CONST . PHP_EOL;
$mc = new MyClass;
// public const
// public const
// protected const
// private const

Other objects

It should be noted that the access modifier is not limited to the instance of the current class. You can also access the private and protected properties and methods of other instances of the current class in the class method:

<?php
class Pointer
{
    public function __construct(private int $x, private  int $y)
    {
    }
    public function add(Pointer $other): Pointer
    {
        $x = $this->x + $other->x;
        $y = $this->y + $other->y;
        return new self($x, $y);
    }
    public function __toString()
    {
        return "({$this->x},{$this->y})";
    }
}
$p1 = new Pointer(1, 3);
$p2 = new Pointer(2, 6);
$p3 = $p1->add($p2);
echo "{$p1}+{$p2}={$p3}" . PHP_EOL;
// (1,3)+(2,6)=(3,9)

The recommendation for using access control characters is that the minimum access principle should be followed. That is, if you can use private, you don't use protected and public, and if you can use protected, you don't use public. Because the properties and methods declared private can be easily modified to protected or public, and the properties and methods declared protected can also be easily modified to public. On the contrary, it cannot. It may require a lot of refactoring of existing code.

Previous contents

Keywords: PHP Back-end

Added by Boo-urns on Tue, 07 Dec 2021 06:04:34 +0200