基础

class

基本类定义以关键字 class 开始,后面跟着类名,再后面跟着一对花括号,花括号中包含类属性和方法的定义。

类名可以是任何有效的标签,只要它不是 PHP 保留字。有效的类名以字母或下划线开头,后面可以跟着任意数量的字母、数字或下划线。作为正则表达式,它可以表示为: ^[a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*$

一个类可以包含它自己的 常量变量(称为“属性”)和函数(称为“方法”)。

示例 #1 简单类定义

<?php
class SimpleClass
{
// 属性声明
public $var = 'a default value';

// 方法声明
public function displayVar() {
echo
$this->var;
}
}
?>

当从对象上下文中调用方法时,伪变量 $this 是可用的。 $this 是调用对象的 value。

警告

静态地调用非静态方法会抛出 Error。在 PHP 8.0.0 之前,这将生成一个弃用通知,并且 $this 将是未定义的。

示例 #2 关于 $this 伪变量的一些示例

<?php
class A
{
function
foo()
{
if (isset(
$this)) {
echo
'$this is defined (';
echo
get_class($this);
echo
")\n";
} else {
echo
"\$this is not defined.\n";
}
}
}

class
B
{
function
bar()
{
A::foo();
}
}

$a = new A();
$a->foo();

A::foo();

$b = new B();
$b->bar();

B::bar();
?>

上面示例在 PHP 7 中的输出

$this is defined (A)

Deprecated: Non-static method A::foo() should not be called statically in %s  on line 27
$this is not defined.

Deprecated: Non-static method A::foo() should not be called statically in %s  on line 20
$this is not defined.

Deprecated: Non-static method B::bar() should not be called statically in %s  on line 32

Deprecated: Non-static method A::foo() should not be called statically in %s  on line 20
$this is not defined.

上面示例在 PHP 8 中的输出

$this is defined (A)

Fatal error: Uncaught Error: Non-static method A::foo() cannot be called statically in %s :27
Stack trace:
#0 {main}
  thrown in %s  on line 27

只读类

从 PHP 8.2.0 开始,类可以使用 readonly 修饰符进行标记。将类标记为 readonly 会将 readonly 修饰符 添加到每个声明的属性,并阻止创建 动态属性。此外,无法使用 AllowDynamicProperties 属性添加对它们的 supports。尝试这样做将触发编译时错误。

<?php
#[\AllowDynamicProperties]
readonly class
Foo {
}

// Fatal error: Cannot apply #[AllowDynamicProperties] to readonly class Foo
?>

由于既没有未类型化的属性也没有静态属性可以标记为 readonly 修饰符,因此只读类也不能声明它们

<?php
readonly class Foo
{
public
$bar;
}

// Fatal error: Readonly property Foo::$bar must have type
?>
<?php
readonly class Foo
{
public static
int $bar;
}

// Fatal error: Readonly class Foo cannot declare static properties
?>

一个 readonly 类可以 扩展,当且仅当子类也是 readonly 类。

new

要创建类的实例,必须使用 new 关键字。除非对象定义了 构造函数,并在错误时抛出 异常,否则始终会创建对象。类应该在实例化之前定义(在某些情况下这是必需的)。

如果包含类名的 字符串 的变量与 new 一起使用,则将创建该类的新的实例。如果类在命名空间中,则执行此操作时必须使用其完全限定名称。

注意:

如果没有参数要传递给类的构造函数,则可以在类名后面省略圆括号。

示例 #3 创建实例

<?php
$instance
= new SimpleClass();

// 这也可以使用变量来完成:
$className = 'SimpleClass';
$instance = new $className(); // new SimpleClass()
?>

从 PHP 8.0.0 开始,支持对任意表达式使用 new。如果表达式产生一个 字符串,这将允许更复杂的实例化。表达式必须用圆括号括起来。

示例 #4 使用任意表达式创建实例

在给定的示例中,我们展示了产生类名的多个有效任意表达式的示例。这显示了对函数的调用、字符串连接和 ::class 常量。

<?php

class ClassA extends \stdClass {}
class
ClassB extends \stdClass {}
class
ClassC extends ClassB {}
class
ClassD extends ClassA {}

function
getSomeClass(): string
{
return
'ClassA';
}

var_dump(new (getSomeClass()));
var_dump(new ('Class' . 'B'));
var_dump(new ('Class' . 'C'));
var_dump(new (ClassD::class));
?>

上面示例在 PHP 8 中的输出

object(ClassA)#1 (0) {
}
object(ClassB)#1 (0) {
}
object(ClassC)#1 (0) {
}
object(ClassD)#1 (0) {
}

在类上下文中,可以通过 new selfnew parent 创建新的对象。

当将已创建的类实例分配给新变量时,新变量将访问与分配的对象相同的实例。将实例传递给函数时,此行为相同。可以通过 克隆 已创建的对象来创建它的副本。

示例 #5 对象赋值

<?php

$instance
= new SimpleClass();

$assigned = $instance;
$reference =& $instance;

$instance->var = '$assigned will have this value';

$instance = null; // $instance and $reference become null

var_dump($instance);
var_dump($reference);
var_dump($assigned);
?>

上面的示例将输出

NULL
NULL
object(SimpleClass)#1 (1) {
   ["var"]=>
     string(30) "$assigned will have this value"
}

可以使用几种方式创建对象的实例

示例 #6 创建新对象

<?php

class Test
{
public static function
getNew()
{
return new static();
}
}

class
Child extends Test {}

$obj1 = new Test(); // 通过类名
$obj2 = new $obj1(); // 通过包含对象的变量
var_dump($obj1 !== $obj2);

$obj3 = Test::getNew(); // 通过类方法
var_dump($obj3 instanceof Test);

$obj4 = Child::getNew(); // 通过子类方法
var_dump($obj4 instanceof Child);

?>

上面的示例将输出

bool(true)
bool(true)
bool(true)

可以使用单个表达式访问新创建对象的成员

示例 #7 访问新创建对象的成员

<?php
echo (new DateTime())->format('Y');
?>

上面的示例将输出类似于

2016

注意: 在 PHP 7.1 之前,如果未定义构造函数,则不会评估参数。

属性和方法

类属性和方法位于不同的“命名空间”中,因此属性和方法可以具有相同的名称。引用属性和方法使用相同的符号,而访问属性还是调用方法,完全取决于上下文,即使用情况是变量访问还是函数调用。

示例 #8 属性访问与方法调用

<?php
class Foo
{
public
$bar = 'property';

public function
bar() {
return
'method';
}
}

$obj = new Foo();
echo
$obj->bar, PHP_EOL, $obj->bar(), PHP_EOL;

上面的示例将输出

property
method

这意味着无法直接调用已分配给属性的匿名函数。相反,必须先将属性分配给变量,例如。可以通过将属性括在括号中来直接调用此类属性。

示例 #9 调用存储在属性中的匿名函数

<?php
class Foo
{
public
$bar;

public function
__construct() {
$this->bar = function() {
return
42;
};
}
}

$obj = new Foo();

echo (
$obj->bar)(), PHP_EOL;

上面的示例将输出

42

extends

一个类可以使用关键字extends在类声明中继承另一个类的常量、方法和属性。不可能扩展多个类;一个类只能从一个基类继承。

继承的常量、方法和属性可以通过重新声明与父类中定义的相同名称来覆盖。但是,如果父类已将方法或常量定义为final,则无法覆盖它们。可以通过使用parent::引用它们来访问覆盖的方法或静态属性。

注意: 从 PHP 8.1.0 开始,常量可以声明为 final。

示例 #10 简单类继承

<?php
class ExtendClass extends SimpleClass
{
// 重新定义父方法
function displayVar()
{
echo
"Extending class\n";
parent::displayVar();
}
}

$extended = new ExtendClass();
$extended->displayVar();
?>

上面的示例将输出

Extending class
a default value

签名兼容性规则

覆盖方法时,其签名必须与父方法兼容。否则,将发出致命错误,或者在 PHP 8.0.0 之前,将生成 E_WARNING 级别错误。如果签名符合方差规则,将强制参数设置为可选,只添加可选的新参数,并且不限制但只放宽可见性,则签名是兼容的。这被称为里氏替换原则,简称 LSP。构造函数private方法不受这些签名兼容性规则的约束,因此在签名不匹配的情况下不会发出致命错误。

示例 #11 兼容的子方法

<?php

class Base
{
public function
foo(int $a) {
echo
"Valid\n";
}
}

class
Extend1 extends Base
{
function
foo(int $a = 5)
{
parent::foo($a);
}
}

class
Extend2 extends Base
{
function
foo(int $a, $b = 5)
{
parent::foo($a);
}
}

$extended1 = new Extend1();
$extended1->foo();
$extended2 = new Extend2();
$extended2->foo(1);

上面的示例将输出

Valid
Valid

以下示例演示子方法删除参数或将可选参数设置为强制参数,与父方法不兼容。

示例 #12 子方法删除参数时出现致命错误

<?php

class Base
{
public function
foo(int $a = 5) {
echo
"Valid\n";
}
}

class
Extend extends Base
{
function
foo()
{
parent::foo(1);
}
}

PHP 8 中上述示例的输出类似于

Fatal error: Declaration of Extend::foo() must be compatible with Base::foo(int $a = 5) in /in/evtlq on line 13

示例 #13 子方法将可选参数设置为强制参数时出现致命错误

<?php

class Base
{
public function
foo(int $a = 5) {
echo
"Valid\n";
}
}

class
Extend extends Base
{
function
foo(int $a)
{
parent::foo($a);
}
}

PHP 8 中上述示例的输出类似于

Fatal error: Declaration of Extend::foo(int $a) must be compatible with Base::foo(int $a = 5) in /in/qJXVC on line 13
警告

在子类中重命名方法的参数不会导致签名不兼容。但是,不建议这样做,因为如果使用命名参数,这将导致运行时Error

示例 #14 在子类中重命名参数时,使用命名参数时出错

<?php

class A {
public function
test($foo, $bar) {}
}

class
B extends A {
public function
test($a, $b) {}
}

$obj = new B;

// 根据 A::test() 契约传递参数
$obj->test(foo: "foo", bar: "bar"); // 错误!

上面的示例将输出类似于

Fatal error: Uncaught Error: Unknown named parameter $foo in /in/XaaeN:14
Stack trace:
#0 {main}
  thrown in /in/XaaeN on line 14

::class

class 关键字也用于类名解析。要获取类 ClassName 的完全限定名,请使用 ClassName::class。这在使用 命名空间 类时特别有用。

示例 #15 类名解析

<?php
namespace NS {
class
ClassName {
}

echo
ClassName::class;
}
?>

上面的示例将输出

NS\ClassName

注意:

使用 ::class 的类名解析是编译时转换。这意味着在创建类名字符串时,还没有发生自动加载。因此,即使类不存在,也会扩展类名。在这种情况下不会发出错误。

示例 #16 缺少类名解析

<?php
print Does\Not\Exist::class;
?>

上面的示例将输出

Does\Not\Exist

从 PHP 8.0.0 开始,::class 也可用于对象。此解析发生在运行时,而不是编译时。其效果与在对象上调用 get_class() 相同。

示例 #17 对象名称解析

<?php
namespace NS {
class
ClassName {
}
}
$c = new ClassName();
print
$c::class;
?>

上面的示例将输出

NS\ClassName

空安全方法和属性

从 PHP 8.0.0 开始,属性和方法也可以使用“空安全”运算符访问:?->。空安全运算符的工作方式与上面的属性或方法访问相同,不同之处在于,如果被解引用的对象是 **null**,则返回 **null**,而不是抛出异常。如果解引用是链的一部分,则会跳过链的其余部分。

其效果类似于首先将每个访问包装在 is_null() 检查中,但更紧凑。

示例 #18 空安全运算符

<?php

// 从 PHP 8.0.0 开始,此行:
$result = $repository?->getUser(5)?->name;

// 等同于以下代码块:
if (is_null($repository)) {
$result = null;
} else {
$user = $repository->getUser(5);
if (
is_null($user)) {
$result = null;
} else {
$result = $user->name;
}
}
?>

注意:

当 null 被认为是属性或方法返回值的有效且预期的可能值时,最好使用空安全运算符。为了指示错误,最好抛出异常。

添加说明

用户贡献说明 11 条说明

aaron at thatone dot com
16 年前
一开始我对对象赋值感到困惑,因为它与普通赋值或引用赋值不太一样。但我认为我已经弄明白了到底是怎么回事。

首先,将 PHP 中的变量视为数据槽。每个槽都是一个指向数据槽的名称,数据槽可以容纳一个基本数据类型的值:数字、字符串、布尔值等。创建引用时,您正在创建另一个指向相同数据槽的名称。将一个变量赋值给另一个变量时,您正在将一个数据槽的内容复制到另一个数据槽。

现在,诀窍是对象实例不像基本数据类型。它们不能直接存储在数据槽中。相反,对象的“句柄”进入数据槽。这是一个标识符,它指向一个特定的对象实例。因此,对象句柄虽然对程序员不可见,但它也是基本数据类型之一。

棘手的地方在于,当您获取一个包含对象句柄的变量,并将其赋值给另一个变量时,另一个变量会获得相同的对象句柄的副本。这意味着两个变量都可以更改相同对象实例的状态。但它们不是引用,因此如果其中一个变量被分配了一个新值,它不会影响另一个变量。

<?php
// 对象赋值
Class Object{
public
$foo="bar";
};

$objectVar = new Object();
$reference =& $objectVar;
$assignment = $objectVar

//
// $objectVar --->+---------+
// |(handle1)----+
// $reference --->+---------+ |
// |
// +---------+ |
// $assignment -->|(handle1)----+
// +---------+ |
// |
// v
// Object(1):foo="bar"
//
?>

$assignment 与 $objectVar 具有不同的数据槽,但其数据槽包含指向同一个对象的句柄。这使得它在某些方面表现得像引用一样。如果使用变量 $objectVar 更改 Object 实例的状态,这些更改也会在 $assignment 下显示,因为它指向同一个 Object 实例。

<?php
$objectVar
->foo = "qux";
print_r( $objectVar );
print_r( $reference );
print_r( $assignment );

//
// $objectVar --->+---------+
// |(handle1)----+
// $reference --->+---------+ |
// |
// +---------+ |
// $assignment -->|(handle1)----+
// +---------+ |
// |
// v
// Object(1):foo="qux"
//
?>

但它与引用并不完全相同。如果将 $objectVar 置空,则用 NULL 替换其数据槽中的句柄。这意味着 $reference 指向相同的数据槽,也将为 NULL。但 $assignment 是一个不同的数据槽,它仍然会保存 Object 实例的句柄副本,因此它不会是 NULL。

<?php
$objectVar
= null;
print_r($objectVar);
print_r($reference);
print_r($assignment);

//
// $objectVar --->+---------+
// | NULL |
// $reference --->+---------+
//
// +---------+
// $assignment -->|(handle1)----+
// +---------+ |
// |
// v
// Object(1):foo="qux"
?>
kStarbe at gmail point com
7 年前
您在第二个示例中开始使用 ::,尽管还没有解释静态概念。当您从基础开始时,这并不容易发现。
Doug
13 年前
$this 和 self 之间有什么区别?

在类定义内部,$this 指的是当前对象,而 self 指的是当前类。

有必要使用 self 来引用类元素,
并使用 $this 来引用对象元素。
还要注意,对象变量的定义必须以关键字开头。

以下示例说明了一些情况

<?php
class Classy {

const
STAT = 'S' ; // 常量没有美元符号(它们始终是静态的)
static $stat = 'Static' ;
public
$publ = 'Public' ;
private
$priv = 'Private' ;
protected
$prot = 'Protected' ;

function
__construct( ){ }

public function
showMe( ){
print
'<br> self::STAT: ' . self::STAT ; // 这样引用(静态)常量
print '<br> self::$stat: ' . self::$stat ; // 静态变量
print '<br>$this->stat: ' . $this->stat ; // 合法,但并非您所想:空结果
print '<br>$this->publ: ' . $this->publ ; // 这样引用对象变量
print '<br>' ;
}
}
$me = new Classy( ) ;
$me->showMe( ) ;

/* 输出如下:
self::STAT: S
self::$stat: Static
$this->stat:
$this->publ: Public
*/
?>
Hayley Watson
6 年前
类名不区分大小写
<?php
class Foo{}
class
foo{} // 致命错误。
?>

可以使用任何大小写形式来引用类
<?php
class bAr{}
$t = new Bar();
$u = new bar();
echo (
$t instanceof $u) ? "true" : "false"; // "true"
echo ($t instanceof BAR) ? "true" : "false"; // "true"
echo is_a($u, 'baR') ? "true" : "false"; // "true"
?>

但是,定义类时使用的大小写形式将被保留为“规范形式”
<?php
echo get_class($t); // "bAr"
?>

并且,始终,“不区分大小写”只适用于 ASCII 字符。
<?php
class пасха{}
class
Пасха{} // 有效
$p = new ПАСХА(); // 未捕获警告。
?>
wbcarts at juno dot com
15 年前
代表“理想世界”的类和对象

如果能通过说 $son->mowLawn() 来完成割草,那不是很棒吗?假设 mowLawn() 函数已定义,并且你的儿子不会抛出错误,那么草坪就会被割掉。

在以下示例中;让 Line3D 类型的对象在三维空间中测量自己的长度。为什么我或 PHP 必须从类外部提供另一个方法来计算长度,而类本身包含所有必要的数据,并且有能力自己进行计算呢?

<?php

/*
* Point3D.php
*
* 代表三维空间中的一个位置,使用 (x, y, z) 坐标系。
*/
class Point3D
{
public
$x;
public
$y;
public
$z; // 此点的 x 坐标。

/*
* 使用从 Point.php 继承的 x 和 y 变量。
*/
public function __construct($xCoord=0, $yCoord=0, $zCoord=0)
{
$this->x = $xCoord;
$this->y = $yCoord;
$this->z = $zCoord;
}

/*
* 此点的 (String) 表示形式为“Point3D(x, y, z)”。
*/
public function __toString()
{
return
'Point3D(x=' . $this->x . ', y=' . $this->y . ', z=' . $this->z . ')';
}
}

/*
* Line3D.php
*
* 使用两个 Point3D 对象代表三维空间中的一个直线。
*/
class Line3D
{
$start;
$end;

public function
__construct($xCoord1=0, $yCoord1=0, $zCoord1=0, $xCoord2=1, $yCoord2=1, $zCoord2=1)
{
$this->start = new Point3D($xCoord1, $yCoord1, $zCoord1);
$this->end = new Point3D($xCoord2, $yCoord2, $zCoord2);
}

/*
* 计算此直线在三维空间中的长度。
*/
public function getLength()
{
return
sqrt(
pow($this->start->x - $this->end->x, 2) +
pow($this->start->y - $this->end->y, 2) +
pow($this->start->z - $this->end->z, 2)
);
}

/*
* 此直线的 (String) 表示形式为“Line3D[start, end, length]”。
*/
public function __toString()
{
return
'Line3D[start=' . $this->start .
', end=' . $this->end .
', length=' . $this->getLength() . ']';
}
}

/*
* 创建并显示 Line3D 类型的对象。
*/
echo '<p>' . (new Line3D()) . "</p>\n";
echo
'<p>' . (new Line3D(0, 0, 0, 100, 100, 0)) . "</p>\n";
echo
'<p>' . (new Line3D(0, 0, 0, 100, 100, 100)) . "</p>\n";

?>

<-- 结果如下 -->

Line3D[start=Point3D(x=0, y=0, z=0), end=Point3D(x=1, y=1, z=1), length=1.73205080757]

Line3D[start=Point3D(x=0, y=0, z=0), end=Point3D(x=100, y=100, z=0), length=141.421356237]

Line3D[start=Point3D(x=0, y=0, z=0), end=Point3D(x=100, y=100, z=100), length=173.205080757]

我最喜欢 OOP 的地方是,“好的”对象会自我约束。我的意思是,现实中也是这样......比如,如果你雇了一名水管工来修理厨房水槽,你不会希望他找出最佳解决方案吗?他不会不喜欢你想要控制整个工作吗?你不会希望他不会给你带来更多问题吗?而且,天哪,要求他离开前打扫一下太过分了吗?

我说,好好设计你的类,这样它们才能不受干扰地完成工作...谁喜欢坏消息?而且,如果你的类和对象定义良好、经过教育并且拥有所有必要的数据来工作(就像上面的例子一样),你就不用从类的外部对整个程序进行微观管理。换句话说...创建一个对象,然后让它大展身手!
moty66 at gmail dot com
14 年前
我希望这将有助于理解如何在类中使用静态变量

<?php

class a {

public static
$foo = 'I am foo';
public
$bar = 'I am bar';

public static function
getFoo() { echo self::$foo; }
public static function
setFoo() { self::$foo = 'I am a new foo'; }
public function
getBar() { echo $this->bar; }
}

$ob = new a();
a::getFoo(); // output: I am foo
$ob->getFoo(); // output: I am foo
//a::getBar(); // fatal error: using $this not in object context
$ob->getBar(); // output: I am bar
// If you keep $bar non static this will work
// but if bar was static, then var_dump($this->bar) will output null

// unset($ob);
a::setFoo(); // The same effect as if you called $ob->setFoo(); because $foo is static
$ob = new a(); // This will have no effects on $foo
$ob->getFoo(); // output: I am a new foo

?>

此致
Motaz Abuthiab
pawel dot zimnowodzki at gmail dot com
2 年前
虽然不存在对不存在的数组键的空安全运算符,但我找到了解决方法:($array['not_existed_key'] ?? null)?->methodName()
关于 stdClass
15 年前
stdClass 是 PHP 默认对象。stdClass 没有属性、方法或父级。它不支持魔术方法,也不实现任何接口。

当将标量或数组强制转换为 Object 时,你会得到一个 stdClass 实例。只要需要通用对象实例,就可以使用 stdClass。
<?php
// 创建 stdClass 实例的方法
$x = new stdClass;
$y = (object) null; // 与上面相同
$z = (object) 'a'; // 创建属性 'scalar' = 'a'
$a = (object) array('property1' => 1, 'property2' => 'b');
?>

stdClass 不是基类!PHP 类不会自动从任何类继承。所有类都是独立的,除非它们显式地扩展另一个类。在这一点上,PHP 与许多面向对象的语言有所不同。
<?php
// CTest 不从 stdClass 派生
class CTest {
public
$property1;
}
$t = new CTest;
var_dump($t instanceof stdClass); // false
var_dump(is_subclass_of($t, 'stdClass')); // false
echo get_class($t) . "\n"; // 'CTest'
echo get_parent_class($t) . "\n"; // false (no parent)
?>

你不能在你的代码中定义名为 'stdClass' 的类。该名称已经被系统使用。你可以定义一个名为 'Object' 的类。

你可以定义一个扩展 stdClass 的类,但你不会有任何好处,因为 stdClass 没有任何作用。

(在 PHP 5.2.8 上测试)
johannes dot kingma at gmail dot com
2 年前
注意!

正如 Hayley Watson 指出的,类名不区分大小写。

<?php
class Foo{}
class
foo{} // 致命错误:无法声明类 foo,因为名称已在使用中
?>
以及
<?php
class BAR{}
$bar = new Bar();
echo
get_class($bar);
?>

是完全可以的,并将返回 'BAR'。

这对类自动加载有影响。标准的 spl_autoload 函数将把类名转换为小写以应对不区分大小写,因此只有当文件名是 bar.php(或在 spl_autoload_extensions(); 中注册了扩展名后,其他变体)时才能找到类 BAR,而不是对于区分大小写的文件和操作系统,例如 Linux,则是 BAR.php。Windows 文件系统区分大小写,但操作系统不区分大小写,因此自动加载 BAR.php 会起作用。
Jeffrey
15 年前
PHP 类可以用于多种用途,但在最基本的层面上,你会使用类来“组织和处理志同道合的数据”。以下是我所说的“组织志同道合的数据”的意思。首先,从无组织数据开始。

<?php
$customer_name
;
$item_name;
$item_price;
$customer_address;
$item_qty;
$item_total;
?>

现在将数据组织到 PHP 类中

<?php
class Customer {
$name; // 与 $customer_name 相同
$address; // 与 $customer_address 相同
}

class
Item {
$name; // 与 $item_name 相同
$price; // 与 $item_price 相同
$qty; // 与 $item_qty 相同
$total; // 与 $item_total 相同
}
?>

现在,以下是我所说的“处理”数据的意思。注意:数据已经组织好,因此这本身就使得编写新函数变得非常容易。

<?php
class Customer {
public
$name, $address; // 此类的 data...

// 用于处理用户输入/验证的函数
// 用于构建输出字符串的函数
// 用于写入数据库的函数
// 用于从数据库读取的函数
// 等等
}

class
Item {
public
$name, $price, $qty, $total; // 此类的 data...

// 用于计算总计的函数
// 用于格式化数字的函数
// 用于处理用户输入/验证的函数
// 用于构建输出字符串的函数
// 用于写入数据库的函数
// 用于从数据库读取的函数
// 等等
}
?>

想象一下,你编写的每个函数只调用该类中的数据部分。某些函数可能会访问所有数据,而其他函数可能只访问一个数据片段。如果每个函数都围绕着内部数据展开,那么你就创建了一个好的类。
匿名
6 年前
起初,我对赋值与引用也很困惑,但最终我弄明白了。这是一个与其中一条评论有些相似的另一个例子,可以帮助那些没有理解第一个例子的读者。想象一下对象实例是房间,你可以在其中存储和操作你的属性和函数。包含对象的变量仅仅保存这个房间的“钥匙”,从而访问对象。当你将这个变量赋给另一个新变量时,你的操作是复制了钥匙并将其交给这个新变量。这意味着这两个变量现在都可以访问同一个“房间”(对象),并因此可以进入并操作值。但是,当你创建引用时,你的操作是让变量共享同一个钥匙。它们都可以访问该房间。如果其中一个变量被赋予一个新钥匙,那么它们共享的钥匙就会被替换,并且它们现在共享一个新的不同的钥匙。这不会影响具有旧钥匙副本的另一个变量……该变量仍然可以访问第一个房间。
To Top