# 基本语法

每个类的定义都以关键字 `class` 开头，后面跟着类名，后面跟着一对花括号，里面包含有类的属性与方法的定义。类名可以是任何非 PHP 保留字的合法标签。一个合法类名以字母或下划线开头，后面跟着若干字母，数字或下划线。一个类可以包含有属于自己的常量，变量（属性）以及函数（方法）。

```php
<?php

class Foo
{
    /**
     * Just a test property.
     *
     * @var string
     */
    public string $property = 'foo';

    /**
     * Just a test method.
     *
     * @param  void
     * @return void
     */
    public function method()
    {
        //
    }
}

```

当一个方法在类定义内部被调用时，有一个可用的伪变量 `$this` 。 `$this` 是一个到主叫对象的引用（通常是该方法所从属的对象，但如果是从第二个对象静态调用时也可能是另一个对象）。

```php
<?php

class Foo
{
    /**
     * Just a test property.
     *
     * @var string
     */
    public string $property = 'foo';

    /**
     * Return the specified property.
     *
     * @param  void
     * @return string
     */
    public function method(): string
    {
        return $this->property;
    }
}

$foo = new Foo();
var_dump($foo->method()); // string(3) "foo"

```

要创建一个类的实例，必须使用 `new` 关键字。当创建新对象时该对象总是被赋值，除非该对象定义了构造函数并且在出错时抛出了一个异常。类应在被实例化之前定义（某些情况下则必须这样）。如果在 `new` 之后跟着的是一个包含有类名的字符串，则该类的一个实例被创建。如果该类属于一个命名空间，则必须使用其完整名称。

```php
<?php

class Foo
{
    //
}

$foo = new Foo();
var_dump($foo); // object(Foo)#1 (0) { }

$foo = 'Foo';
$foo = new $foo;
var_dump($foo); // object(Foo)#1 (0) { }

$foo = new Foo();
$foo = new $foo;
var_dump($foo); // object(Foo)#1 (0) { }

```

在类定义内部，可以用 `new self` 创建新对象。

```php
<?php

class Foo
{
    /**
     * Return an instance of the current class.
     *
     * @param  void
     * @return Foo
     */
    public static function method(): Foo
    {
        return new self;
    }
}

var_dump(Foo::method()); // object(Foo)#1 (0) { }

```

在类定义内部，可以用 `new parent` 创建新对象。

```php
<?php

class Foo
{
    //
}

class Bar extends Foo
{
    /**
     * Return an instance of the parent class.
     *
     * @param  void
     * @return Foo
     */
    public static function method(): Foo
    {
        return new parent;
    }
}

var_dump(Bar::method()); // object(Foo)#1 (0) { }

```

在类定义内部，可以用 `new static` 创建新对象。

```php
<?php

class Foo
{
    /**
     * Return an instance of the late static binding class.
     *
     * @param  void
     * @return Foo
     */
    public static function method(): Foo
    {
        return new static;
    }
}

class Bar extends Foo
{
    //
}

$foo = Foo::method();
var_dump($foo); // object(Foo)#1 (0) { }

$bar = Bar::method();
var_dump($bar); // object(Bar)#2 (0) { }

```

当把一个对象已经创建的实例赋给一个新变量时，新变量会访问同一个实例，就和用该对象赋值一样。

```php
<?php

class Foo
{
    //
}

$foo = new Foo();
$bar = $foo;
$baz = &$foo;
$foo = null;
var_dump($foo); // NULL
var_dump($bar); // object(Foo)#1 (0) { }
var_dump($baz); // NULL

```

可以通过一个表达式来访问新创建对象的成员。

```php
<?php

class Foo
{
    /**
     * Just a test property.
     *
     * @var string
     */
    public string $property = 'foo';
}

var_dump((new Foo())->property); // string(3) "foo"

```

类中的属性和方法存在于单独的“名称空间”中，因此可以使用具有相同名称的属性和方法。

```php
<?php

class Foo
{
    /**
     * Just a test property.
     *
     * @var string
     */
    public string $test = 'property';

    /**
     * Return a string.
     *
     * @param  void
     * @return string
     */
    public function test(): string
    {
        return 'method';
    }
}

$foo = new Foo();
var_dump($foo->test);   // string(8) "property"
var_dump($foo->test()); // string(6) "method"

```

调用存储在属性中的匿名函数。

```php
<?php

class Foo
{
    /**
     * Store an anonymous function.
     *
     * @var callable
     */
    public $property;

    /**
     * Store an anonymous function to the property.
     *
     * @param  void
     * @return void
     */
    public function __construct()
    {
        /**
         * Return a string.
         *
         * @param  void
         * @return string
         */
        $this->property = function (): string {
            return 'foo';
        };
    }
}

$foo = new Foo();
$method = $foo->property;
var_dump($method());          // string(3) "foo"
var_dump(($foo->property)()); // string(3) "foo"

```

一个类可以在声明中用 `extends` 关键字继承另一个类的方法和属性。 PHP 不支持多重继承，一个类只能继承一个基类。被继承的方法和属性可以通过用同样的名字重新声明来覆盖。但是如果父类定义方法时使用了 `final` ，则该方法不可被覆盖。可以通过 `parent::` 来访问被覆盖的方法或属性。当覆盖方法时，参数必须保持一致否则 PHP 将发出 `E_STRICT` 级别的错误信息。但构造函数例外，构造函数可在被覆盖时使用不同的参数。

```php
<?php

class Foo
{
    /**
     * Return a string.
     *
     * @param  void
     * @return void
     */
    public function method(): string
    {
        return 'foo';
    }
}

class Bar extends Foo
{
    /**
     * Override the parent method.
     *
     * @param  void
     * @return string
     */
    public function method(): string
    {
        return 'bar';
    }
}

$bar = new Bar();
var_dump($bar->method()); // string(3) "bar"

```

关键字 `class` 也可用于类名的解析。使用关键字 `class` 可以获取一个字符串，包含了类的完全限定名称。这对使用了命名空间的类尤其有用。

```php
<?php

namespace Foo;

class Bar
{
    //
}

var_dump(Bar::class); // string(7) "Foo\Bar"

```

