1

I have notification classes called ProductNotification, OrderNotification, etc, these have a mail method which returns another class which holds further data for the sending of emails:

class ProductNotification {
    public function mail()
    {
        return ProductMail::class;
    }
}
class OrderNotification {
    public function mail()
    {
        return OrderMail::class;
    }
}

Is there a way to instantiate the ProductMail class from the method, the following doesn't work and I'm not sure how to pass through another variable $data to the constructo.?

class BaseNotification {
    public function toMail()
    {
        return (new $this->mail())->to($email)->send();
    {
}

I know that if mail() was a property on the class instead, that this would be possible and I can pass through $data to the constructor as the following works, but is this possible from a method?

class ProductNotification {
    public $mail = ProductMail::class;
}
class BaseNotification {
    public function toMail()
    {
        return (new $this->mail($data))->to($email)->send();
    {
}
4
  • Any reason not to have mail() method return new ProductMail();? Commented Dec 3, 2021 at 23:31
  • Or store the class as a property instead of a method return. Commented Dec 3, 2021 at 23:32
  • You could store the class as a local variable in toMail and then instantiate the variable. Commented Dec 3, 2021 at 23:33
  • Because I need to pass $data through to the ProductMail constructor, I've already shown that I am aware that I can store it as a property. But because of the way other parts of the class is structured, it would be cleaner to keep things consistent by keeping it as a method. Commented Dec 3, 2021 at 23:34

2 Answers 2

1

You can store the class as a local variable in the toMail method and then instantiate it.

class BaseNotification {
    public function toMail($data)
    {
        $mail_class = $this->mail();

        return new $mail_class($data);
    }
}
Sign up to request clarification or add additional context in comments.

1 Comment

No idea why I didn't think of this, I guess tunnel vision and coding late in to the night after a hard days work. Thanks!
0

You can't instantiate an object from a method call, but you can do so from a variable. So just assign the method's return call to a variable:

class ProductNotification extends BaseNotification {
    public function mail() {
        return ProductMail::class;
    }
}

class OrderNotification extends BaseNotification {
    public function mail() {
        return OrderMail::class;
    }
}

class BaseNotification {
    public function toMail()
    {
        $data = [];
        $class = $this->mail();
        return (new $class($data))->to($email)->send();
    {
}

Though it might be cleaner to just use the mail() method to build the mail:

class ProductNotification extends BaseNotification {
    public function mail($data) {
        return new ProductMail($data);
    }
}

class OrderNotification extends BaseNotification {
    public function mail($data) {
        return new OrderMail($data);
    }
}

class BaseNotification {
    public function mail() {
        throw new \Exception("not implemented");
    }

    public function toMail()
    {
        $data = [];
        return $this->mail($data)->to($email)->send();
    {
}

1 Comment

You're the Michael Jordan of getting in just too late :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.