Page 1 of 1
newinstance() unfriendly in simple inheritance situations
Posted: Wed Apr 01, 2009 2:04 pm
by gmorehoudh
Just spent a good amount of time trying to figure out why a class I created by extending Swift_Mailer in order to wrap the send() function was not working.
Turns out the ::newInstance() call mentioned here (and elsewhere) in the docs --
http://swiftmailer.org/docs/sending-quickref -- returns a Swift_Mailer instance, not my extended class. I simply replaced the instantiation of my class from 'my_class::newInstance($transport)' to 'new my_class($transport)' which is the standard way of doing things in PHP. You may wish to note everywhere in the documentation where it might be relevant that one must either use the standard way of creating new objects, or override newInstance(), when creating classes that extend parts of Swift. It'd be helpful to people who are not familiar with the newInstance() idiom.
Re: newinstance() unfriendly in simple inheritance situations
Posted: Wed Apr 01, 2009 2:24 pm
by josh
Either that or introduce a configuration parameter to allow the user to substitute a class name
Re: newinstance() unfriendly in simple inheritance situations
Posted: Wed Apr 01, 2009 7:12 pm
by Chris Corbyn
This is a problem with PHP and lack of late static binding. PHP 5.3 will allow what you were doing to work correctly.
Everywhere I use newInstance() in Swift Mailer, the "new" keyword can be used too, I just advertise the use of newInstance() for a couple of reasons:
1) It's more likely to scale if I need to change the way the object is created
2) It's the only way you can chain off of the constructor, which I do quite a bit in the documentation.
I'll add something to the docs to mention that the new keyword is also allowed.
On a side note, Swift Mailer is designed so that you shouldn't have to override the send() method and if you're doing this to say, write the mail to a database instead then the "best" course of action is to use composition and write a new Transport. Transports are really simple:
Code: Select all
interface Swift_Transport {
function start();
function stop();
function isStarted();
function send(Swift_Mime_Message $message);
}
If your intention is to add some logic before or after an extisting transport runs then just wrap it:
Code: Select all
$myTransport = new MyTransport(new Swift_SmtpTransport(...));
/* ....
Class MyTransport ....
function send(Swift_Mime_Message $message)
{
$this->doSomething();
return $this->_delegate->send($message);
}
...
*/
Re: newinstance() unfriendly in simple inheritance situations
Posted: Mon Apr 06, 2009 2:36 pm
by gmorehoudh
Thanks Chris, I will take a look at doing it this way. We are adding logic to divert outbound mail to ourselves if the code is running on one of our development workstations as opposed to the production server.
Re: newinstance() unfriendly in simple inheritance situations
Posted: Thu Apr 23, 2009 8:57 pm
by gmorehoudh
Say, what's that _delegate bit in there?
Re: newinstance() unfriendly in simple inheritance situations
Posted: Sat May 02, 2009 5:58 am
by Chris Corbyn
gmorehoudh wrote:Say, what's that _delegate bit in there?
The _delegate bit is the transport that the work will be delegated to

It's another common design pattern. For everything you don't care about or don't want to modify, just pass the invocation along to the delegate. For everything you do care about or want to change the behaviour of, add some custom logic, and possibly call the delegate.
Code: Select all
class MyTransport implements Swift_Transport {
private $_delegate;
public function __construct(Swift_Transport $delegate) {
$this->_delegate = $delegate;
}
public function isStarted() {
return $this->_delegate->isStarted();
}
public function start() {
return $this->_delegate->start();
}
public function stop() {
return $this->_delegate->stop();
}
public function send(Swift_Mime_Message $message) {
$this->_doSomething(); //Customized behaviour
return $this->_delegate->send($message); //Delegation
}
private function _doSomething() {
echo "Hey, I've customized this send() thingy";
}
}
$delegate = Swift_SmtpTransport::newInstance('localhost', 25);
$mailer = new Swift_Mailer(new MyTransport($delegate));