PHP 构造函数的用途
Posted
技术标签:
【中文标题】PHP 构造函数的用途【英文标题】:Purpose of PHP constructors 【发布时间】:2011-03-03 05:55:29 【问题描述】:我正在处理类和对象类结构,但不是在复杂的层次上——只是类和函数,然后在一个地方进行实例化。
至于__construct
和__destruct
,请很简单的告诉我:构造函数和析构函数的目的是什么?
我知道学校层面的理论解释,但我期待在现实世界中出现类似的情况,比如我们必须在哪些情况下使用它们。
请提供一个例子。
问候
【问题讨论】:
eac 例子真的很好,现在我有点明白为什么人们在寻找构造函数和析构函数,但是告诉我,如果我不使用构造函数,我会丢失任何东西......我们使用的程序中的 bcoz很多函数,变量等等..对于函数和变量,我如何使用构造,那里有没有动态分配,意味着我们应该在构造函数中调用所有函数名, 不接受的可能原因是什么......回答......我发现那里回答真的回答问题 【参考方案1】:构造函数是在对象初始化后执行的函数(分配的内存、复制的实例属性等)。其目的是使对象处于有效状态。
通常,要处于可用状态的对象需要一些数据。构造函数的目的是在实例化时强制将此数据提供给对象,并禁止任何没有此类数据的实例。
考虑一个简单的类,它封装了一个字符串,并且有一个方法可以返回这个字符串的长度。一种可能的实现是:
class StringWrapper
private $str;
public function setInnerString($str)
$this->str = (string) $str;
public function getLength()
if ($this->str === null)
throw new RuntimeException("Invalid state.");
return strlen($this->str);
为了处于有效状态,此函数需要在getLength
之前调用setInnerString
。通过使用构造函数,您可以在调用getLength
时强制所有实例处于良好状态:
class StringWrapper
private $str;
public function __construct($str)
$this->str = (string) $str;
public function getLength()
return strlen($this->str);
您还可以保留setInnerString
以允许在实例化后更改字符串。
当对象即将从内存中释放时调用析构函数。通常,它包含清理代码(例如,关闭对象持有的文件描述符)。它们在 php 中很少见,因为 PHP 在脚本执行结束时会清理脚本持有的所有资源。
【讨论】:
另一种说法是“将对象置于有效状态”是说“确保对象不变量为真”。类的不变量是关于实例的事实应该始终为真:就像内部 str 值应该始终被初始化。【参考方案2】:通过例子学习:
class Person
public $name;
public $surname;
public function __construct($name,$surname)
$this->name=$name;
$this->surname=$surname;
为什么这有帮助?因为不是:
$person = new Person();
$person->name='Christian';
$person->surname='Sciberras';
你可以使用:
$person = new Person('Christian','Sciberras');
代码更少,看起来更干净!
注意:正如下面的回复正确指出的那样,构造函数/析构函数用于各种各样的事情,包括:变量的解/初始化(特别是当值是变量时)、内存解/分配、不变量(可能是超越)和更清洁的代码。 我还想指出,“更简洁的代码”不仅仅是“糖”,而是增强了可读性、可维护性等。
【讨论】:
除了对公共属性的可疑使用之外,我认为这个答案没有抓住重点。构造函数不只是看起来暗示的语法糖,它们是一种强制不变量的方法。 它不仅看起来更干净。它可以防止错误:如果您忘记设置姓氏会怎样?构造函数强迫你这样做。 OP要求一个真实的例子,我展示了一个。使用公共属性是为了使示例对这两种情况都有效。我的回答没有遗漏任何一点。构造函数可以用于任何东西(包括你提到的)来设置默认变量。快速示例:class A protected $path;公共函数 __construct() $this->path=getcwd().'path'; 【参考方案3】:构造函数在您实例化类的实例时运行。所以如果你有课Person
:
class Person
public $name = 'Bob'; // this is initialization
public $age;
public function __construct($name = '')
if (!empty($name))
$this->name = $name;
public function introduce()
echo "I'm $this->name and I'm $this->age years old\n";
public function __destruct()
echo "Bye for now\n";
演示:
$person = new Person;
$person->age = 20;
$person->introduce();
// I'm Bob and I'm 20 years old
// Bye for now
我们可以通过构造函数参数覆盖初始化设置的默认值:
$person = new Person('Fred');
$person->age = 20;
$person->introduce();
// if there are no other references to $person and
// unset($person) is called, the script ends
// or exit() is called __destruct() runs
unset($person);
// I'm Fred and I'm 20 years old
// Bye for now
希望这有助于演示构造函数和析构函数的调用位置,它们有什么用处?
__construct()
可以默认类成员具有资源或更复杂的数据结构。
__destruct()
可以释放文件和数据库句柄等资源。
构造函数常用于class composition或constructor injection of required dependencies。
【讨论】:
【参考方案4】:类的构造函数定义了当你从这个类实例化一个对象时会发生什么。类的析构函数定义了当你销毁对象实例时会发生什么。
见PHP Manual on Constructors and Destructors:
PHP 5 允许开发人员为类声明构造方法。具有构造方法的类在每个新创建的对象上调用此方法,因此它适用于对象在使用之前可能需要的任何初始化。
和
PHP 5 引入了与其他面向对象语言(例如 C++)类似的析构函数概念。一旦对特定对象的所有引用被删除或对象被显式销毁或以关闭序列中的任何顺序调用,就会调用析构函数方法。
在实践中,您使用构造函数将对象置于最小有效状态。这意味着您将传递给构造函数的参数分配给对象属性。如果您的对象使用某种不能直接分配为属性的数据类型,您可以在此处创建它们,例如
class Example
private $database;
private $storage;
public function __construct($database)
$this->database = $database;
$this->storage = new SplObjectStorage;
请注意,为了让您的对象可测试,a constructor should not do any real work:
在构造函数中工作,例如:创建/初始化协作者,与其他服务通信,以及设置自己的状态的逻辑删除测试所需的接缝,强制子类/模拟继承不需要的行为。构造函数中的过多工作会阻止实例化或更改测试中的协作者。
在上面的Example
中,$database
是一个合作者。它有自己的生命周期和目的,并且可能是共享实例。您不会在构造函数中创建它。另一方面,SplObjectStorage
是Example
的组成部分。它具有完全相同的生命周期,并且不与其他对象共享。因此,可以在ctor中new
它。
同样,你使用析构函数来清理你的对象。在大多数情况下,这是不需要的,因为它是由 PHP 自动处理的。这就是为什么你会在野外看到的 ctor 比 dtor 多得多。
【讨论】:
好吧抱歉,假设例如,缓存的基本目的是提高网站性能,即使我可以监控这个缓存概念,我们也可以在一个文件中执行查询时显示实时,我们复制记录和下次用户尝试点击记录时,系统将只查看文件而不是实时数据库,有没有像你这样的例子,请 @Bharanikumar 这与您在上面提出的问题完全不同。如果您需要缓存,请查看 APC 或 memcache 并研究一些代码示例,例如 Zend_Cache。 其实我知道缓存。不不...为了容易理解有人可以说像缓存这样的例子,我问过这个问题,但现在我也有很多例子,【参考方案5】:当我想到构造函数之前的 new
关键字时,我发现它最容易掌握:它只是告诉我的变量一个其数据类型的新对象将根据我调用的构造函数和我传递给它的内容,我可以在到达时定义对象的状态。
如果没有新对象,我们将生活在null
的土地上,然后崩溃!
从 C++ 的角度来看,析构函数是最明显的,如果你没有析构函数方法删除所有指向的内存,它将在程序退出后继续使用,导致泄漏并在客户端操作系统上滞后,直到下次重新启动。
我确信这里有足够多的好信息,但从我所注意到的情况来看,另一个角度总是有帮助的!
【讨论】:
关于泄漏部分,不准确。当您退出程序时,任何泄漏都会被删除(除非内存驻留在另一个程序中)。内存泄漏主要是在程序使用期间造成的,而不是在程序退出时。例如,我曾经有一个程序在使用 1 小时内泄漏了 700Mb。但关闭后一切恢复正常。【参考方案6】:构造函数是类的函数,在创建类的对象时自动执行我们不需要单独调用该构造函数,我们可以将构造函数称为魔术方法,因为在 php 中魔术方法以双下划线字符开头
【讨论】:
以上是关于PHP 构造函数的用途的主要内容,如果未能解决你的问题,请参考以下文章