When a class extends another class and also implements an interface, shouldn't it override all the abstract methods of the parent class and interface?

huangapple go评论72阅读模式
英文:

When a class extends another class and also implements an interface, shouldn't it override all the abstract methods of the parent class and interface?

问题

根据我所知,当一个类扩展另一个类时,它应该覆盖父类的所有抽象方法,同时也可以覆盖非抽象方法。而当一个类实现一个接口时,它应该覆盖所有父接口的方法。但是我曾经看到一个 Laravel 项目没有这样做。

这是父接口:

<?php

interface MustVerifyEmail
{
    /**
     * 确定用户是否已验证其电子邮件地址。
     *
     * @return bool
     */
    public function hasVerifiedEmail();

    /**
     * 将给定用户的电子邮件标记为已验证。
     *
     * @return bool
     */
    public function markEmailAsVerified();

    /**
     * 发送电子邮件验证通知。
     *
     * @return void
     */
    public function sendEmailVerificationNotification();

    /**
     * 获取应用于验证的电子邮件地址。
     *
     * @return string
     */
    public function getEmailForVerification();
}

这是父类:

<?php

class User extends Model implements
    AuthenticatableContract,
    AuthorizableContract,
    CanResetPasswordContract
{
    use Authenticatable, Authorizable, CanResetPassword, MustVerifyEmail;
}

这是子类:

<?php

use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable implements MustVerifyEmail
{
    /**
     * 可以批量赋值的属性。
     *
     * @var array<int, string>
     */
    protected $fillable = [
        'name',
        'email',
        'password',
    ];

    /**
     * 应该在序列化时隐藏的属性。
     *
     * @var array<int, string>
     */
    protected $hidden = [
        'password',
    ];

    /**
     * 应该被转换的属性。
     *
     * @var array<string, string>
     */
    protected $casts = [
        'email_verified_at' => 'datetime',
        'password' => 'hashed',
    ];

    public function activeCode()
    {
        return //...
    }

    public function hasTwoFactor($key)
    {
        return //...
    }

    public function isTwoFactorAuthEnabled()
    {
        return //...
    }
}

这是为什么会发生这种情况的原因呢?

英文:

As far as I know,
when a class extending another class, It's should override all abstract methods of parent class and It can also override non-abstract methods
And also when a class implementing an interface, It's should override all of the parent interface methods
but I've seen a Laravel project that didn't do this

This is the parent interface:

&lt;?php

interface MustVerifyEmail
{
    /**
     * Determine if the user has verified their email address.
     *
     * @return bool
     */
    public function hasVerifiedEmail();

    /**
     * Mark the given user&#39;s email as verified.
     *
     * @return bool
     */
    public function markEmailAsVerified();

    /**
     * Send the email verification notification.
     *
     * @return void
     */
    public function sendEmailVerificationNotification();

    /**
     * Get the email address that should be used for verification.
     *
     * @return string
     */
    public function getEmailForVerification();
}

this is the parent class:

&lt;?php

class User extends Model implements
    AuthenticatableContract,
    AuthorizableContract,
    CanResetPasswordContract
{
    use Authenticatable, Authorizable, CanResetPassword, MustVerifyEmail;
}

and this is the child class:

&lt;?php

use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable implements MustVerifyEmail
{
    /**
     * The attributes that are mass assignable.
     *
     * @var array&lt;int, string&gt;
     */
    protected $fillable = [
        &#39;name&#39;,
        &#39;email&#39;,
        &#39;password&#39;,
    ];

    /**
     * The attributes that should be hidden for serialization.
     *
     * @var array&lt;int, string&gt;
     */
    protected $hidden = [
        &#39;password&#39;,
    ];

    /**
     * The attributes that should be cast.
     *
     * @var array&lt;string, string&gt;
     */
    protected $casts = [
        &#39;email_verified_at&#39; =&gt; &#39;datetime&#39;,
        &#39;password&#39; =&gt; &#39;hashed&#39;,
    ];

    public function activeCode()
    {
        return //...
    }

    public function hasTwoFactor($key)
    {
        return //...
    }

    public function isTwoFactorAuthEnabled()
    {
        return //...
    }
}

How did this happen?

答案1

得分: 0

TLDR:用户模型继承了其父模型的实现,而后者将实现委托给trait MustVerifyEmail

这些方法实际上是显式实现的,只是不是在类本身上实现,而是在其traits上实现。

Traits 是一种在单继承语言(如 PHP)中进行代码重用的机制。Trait 旨在通过使开发人员能够在位于不同类层次结构的多个独立类中自由重用方法集来减少单继承的某些限制。(来源自 PHP 的 Traits)

在这种特定情况下,您可能会被两个同名的面向对象编程结构所困惑:interface MustVerifyEmailtrait MustVerifyEmail。您的用户模型声明将由它来实现接口,这是正确的,但不严格,因为实际执行它的是父类Authenticatable但是它是何时执行的? 这就是use关键字起作用的地方:

虽然implements用于接口,但use用于Trait。父用户类正在“使用”trait MustVerifyEmail,换句话说,它将Trait附加到自身,因此“继承”了所有方法。

英文:

TLDR: User model inherits the implementation from its parent model, while the later delegated the implementation to trait MustVerifyEmail.


These methods were actually explicitly implemented, just not on the class itself but on its traits.

> Traits are a mechanism for code reuse in single inheritance languages such as PHP. A Trait is intended to reduce some limitations of single inheritance by enabling a developer to reuse sets of methods freely in several independent classes living in different class hierarchies. (From PHP's Traits)

In this particular case you might be confused by two homonym oop structures: interface MustVerifyEmail vs trait MustVerifyEmail. Your User model states that the interface will be implemented by it, which is true but not strictly because the one actually implementing it is the parent class Authenticatable. But when did it implement it? That is where the use keyword gets into action:

While implements is for Interfaces, the use is for Traits. Parent User class is "using" the trait MustVerifyEmail, in other words, it is attaching the trait to itself, thus "inheriting" all of its methods.

答案2

得分: -1

在Laravel中,您可以在不明确声明接口中的所有方法的情况下实现接口。相反,Laravel 使用"隐式实现",其中框架根据命名约定和方法签名动态解析实现。

英文:

In Laravel, you can implement interfaces without explicitly declaring all the methods of the interface in your class. Instead, Laravel uses "implicit implementation," where the framework dynamically resolves the implementation based on naming conventions and method signatures.

huangapple
  • 本文由 发表于 2023年7月12日 20:41:01
  • 转载请务必保留本文链接:https://go.coder-hub.com/76670662.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定