首页 » SEO优化 » php中parent技巧_PHP关键字SelfStatic和parent的差异

php中parent技巧_PHP关键字SelfStatic和parent的差异

访客 2024-11-10 0

扫一扫用手机浏览

文章目录 [+]

在我第一次作为开拓职员开始事情后的很长一段韶光里,我认为static::和self::是完备一样的。

parent::是什么?

假设我们有一个BaseTestCase类,它有一个setUp方法:

php中parent技巧_PHP关键字SelfStatic和parent的差异

class BaseTestCase{ public function setUp(): void { echo 'Run base test case set up here...'; }} (new BaseTestCase())->setUp(); // Output is: "Run base test case set up here...';

正如我们所看到的,当我们调用 setUp 方法时,它按预期运行并输出文本。

php中parent技巧_PHP关键字SelfStatic和parent的差异
(图片来自网络侵删)

现在,让我们假设我们想要创建一个新的FeatureTest类来继续BaseTestCase类。
如果我们想运行FeatureTest类的setUp方法,我们可以这样做:

class FeatureTest extends BaseTestCase{ //} (new FeatureTest())->setUp(); // Output is: "Run base test case set up here...";

正如我们所看到的,我们没有在FeatureTest中定义setUp方法,以是在BaseTestCase中定义的方法将被运行。

现在,假设我们想在运行FeatureTest中的setUp方法时运行一些额外的逻辑。
例如,如果这些类是作为PhpUnit测试的一部分利用的测试用例,那么我们可能须要在数据库中创建模型或设置测试值。

一开始,你可能(缺点地)认为你可以在你的FeatureTest方法中定义setUp方法,然后调用$this->setUp()。
诚笃说,当我第一次学习编程的时候,我总是陷入这个陷阱!

以是我们的代码可能看起来像这样:

class FeatureTest extends BaseTestCase{ public function setUp(): void { $this->setUp(); echo 'Run extra feature test set up here...'; }} (new FeatureTest())->setUp();

但是,您会创造,如果我们运行这段代码,我们终极会陷入一个循环,导致您的运用程序崩溃。
这是由于我们递归地哀求setUp一遍又一各处调用它自己。
你可能会得到类似这样的输出:

Fatal error: Out of memory (allocated 31457280 bytes) (tried to allocate 262144 bytes) in /in/1MXtt on line 15mmap() failed: [12] Cannot allocate memorymmap() failed: [12] Cannot allocate memoryProcess exited with code 255.

因此,我们须要见告PHP在BaseTestCase中利用setUp方法,而不是利用$this->setUp()。
为了做到这一点,我们可以像这样用parent::setUp()更换$this->setUp():

class FeatureTest extends BaseTestCase{ public function setUp(): void { parent::setUp(); echo 'Run extra feature test set up here...'; }} (new FeatureTest())->setUp(); // Output is: "Run base test case set up here... Run extra feature test set up here...";

现在,正如你所看到的,当我们在FeatureTest类中运行setUp方法时,我们首先运行BaseTestCase中的代码,然后连续运行子类中定义的别的代码。

值得把稳的是,您并不总是须要将parent::调用放在方法的顶部。
实际上,您可以将其放置在方法中任何最适宜代码目的的位置。
例如,如果你想先在FeatureTest类中运行你的代码,然后在BaseTestCase类中运行,你可以像这样将parent::setUp()调用移动到方法的底部:

self::是什么?

假设我们有一个Model类,它有一个静态的connection属性和一个makeConnection方法。
我们还可以想象我们有一个User类,它继续了Model类并覆盖了connection属性。

这两个类可能看起来像这样:

class Model{ public static string $connection = 'mysql'; public function makeConnection(): void { echo 'Making connection to: '.self::$connection; }} class User extends Model{ public static string $connection = 'postgres';}

现在让我们在两个类上运行makeConnection方法,看看我们会得到什么输出:

(new Model())->makeConnection(); // Output is: "Making connection to mysql" (new User())->makeConnection(); // Output is: "Making connection to mysql";

正如我们所看到的,这两个调用都导致了Model类的connection属性被利用。
这是由于self利用了在方法所在的类上定义的属性。
在这两种情形下,makeConnection方法在Model类上是打开的,由于User类上不存在一个方法。

为了进一步解释这一点,我们将向User类添加makeConnection方法,如下所示:

class Model{ public static string $connection = 'mysql'; public function makeConnection(): void { echo 'Making connection to: '.self::$connection; }} class User extends Model{ public static string $connection = 'postgres'; public function makeConnection(): void { echo 'Making connection to: '.self::$connection; }}

现在,如果我们再次调用这两个方法,我们会得到以下输出:

(new Model())->makeConnection(); // Output is: "Making connection to mysql" (new User())->makeConnection(); // Output is: "Making connection to postgres";

正如您所看到的,对makeConnection的调用现在将利用User类上的connection字段,由于这是该方法存在的地方。

static::是什么?

现在我们已经知道了self::的浸染,让我们来看看static::。

为了更好地理解它的浸染,让我们更新上面的代码示例,利用static::而不是self::,如下所示:

class Model{ public static $connection = 'mysql'; public function makeConnection() { echo 'Making connection to: '.static::$connection; }} class User extends Model{ public static $connection = 'postgres';}

如果我们在两个类上运行makeConnection方法,我们会得到以下输出:

(new Model())->makeConnection(); // Output is: "Making connection to mysql" (new User())->makeConnection(); // Output is: "Making connection to postgres";

正如我们所看到的,这个输出与我们之前利用self::$connection时不同。
对User类上的makeConnection方法的调用利用了User类上的connection属性,而不是Model类(该方法实际所属的类)。
这是由于PHP中一个名为“后期静态绑定”的特性。

如果您有兴趣阅读更多关于后期静态绑定的内容,可以在这里查看PHP文档。
https://www.php.net/manual/en/language.oop5.late-static-bindings.php

根据PHP文档:这个特性被命名为“后期静态绑定”,从内部的角度考虑。
“后期绑定”来自若许一个事实,即static::将不会利用定义方法的类来解析,而是利用运行时信息来打算。
它也被称为“静态绑定”,由于它可以用于(但不限于)静态方法调用。
"

因此,在我们的示例中,利用了User类上的connection属性,由于我们在同一个类上调用了makeConnection方法。

然而,值得把稳的是,如果connection属性在User类上不存在,它将回退到利用Model类上的属性。

什么时候利用self::或 static::?

现在我们对self::和static::之间的差异有了一个大致的理解,让我们快速先容一下如何决定在自己的代码中利用哪一个。

这统统都取决于您正在编写的代码的用例。

一样平常来说,我常日会利用static::而不是self::,由于我希望我的类是可扩展的

例如,假设我想写一个类,我完备打算由子类继续(例如上面示例中的BaseTestCase类)。
除非我真的想防止子类重写属性或方法,否则我想利用static::。

这意味着我可以有信心,如果我重写任何静态方法或字段,我的子类将利用我的重写。
我无法见告你有多少次我在代码中碰着了bug,当我在父类中利用self::时,然后无法弄清楚为什么我的子类没有利用我的重写!

另一方面,一些开拓职员可能会争辩说,你该当坚持利用self::,由于你不应该真的从类继续。
他们可能会建议你该当遵照“组合优于继续”的原则。
我不会深入研究这个话题,由于这是未来的另一篇博客文章。
但从广义上说,大略地说,这个原则指出,你该当避免通过将所有逻辑放在父类中来为类添加功能,而是通过用许多更小的类来构建类来添加功能。

这意味着如果你遵照这个原则,你就不须要利用static::,由于你永久不会扩展你的父类。
如果你想确保类不能被扩展,你乃至可以更进一步,在定义类时利用final关键字。
利用final关键字可以防止类被继续,以是它可以减少您对类可能意外扩展并引入任何潜在缺点的担忧。

一样平常来说,最好在编写代码时根据详细情形决定该当利用static::还是self::。

相关文章

我国土地利用分类代码的构建与应用

土地利用分类代码是我国土地管理的重要组成部分,是土地资源调查、规划、利用和保护的依据。土地利用分类代码的构建与应用显得尤为重要。本...

SEO优化 2025-02-18 阅读0 评论0

微信跳转微信支付便捷支付体验的秘密武器

移动支付已成为人们日常生活中不可或缺的一部分。作为我国领先的社交平台,微信支付凭借其便捷、安全的支付方式,深受广大用户的喜爱。而微...

SEO优化 2025-02-18 阅读0 评论0

探寻会计科目代码背后的奥秘分类与

会计科目代码是会计信息系统中不可或缺的组成部分,它将企业的经济活动进行分类和归纳,为会计核算、财务分析和决策提供重要依据。本文将从...

SEO优化 2025-02-18 阅读1 评论0