7
\$\begingroup\$

I have a class whose purpose is to display a comment. I'd like to be able to instantiate it by passing a Comment object if I happen to have it available, or just the values if that's what I have available at the time. Unfortunately PHP doesn't allow overloaded constructors, so here's the workaround I came up with.

class CommentPanel extends Panel {
    //Private Constructor, called only from MakeFrom methods
    private function CommentPanel($text, $userName, $timestamp) {
        parent::Panel(0, $top, System::Auto, System::Auto);

        // Render comment
    }

    public static function MakeFromObject(Comment $comment) {
        return new CommentPanel($comment->text, $comment->User->nickname, $comment->last_updated_ts);
    }

    public static function MakeFromValues($text, $userName, $timestamp) {
        return new CommentPanel($text, $userName, $timestamp);
    }
}

So here's the two methods for instantiating a CommentPanel:

$cp = CommentPanel::MakeFromObject($comment);
// or...
$cp = CommentPanel::MakeFromValues($text, $user, $last_updated_ts);
// but not
$cp = new CommentPanel(); //Runtime error

I'm moderately satisfied, although it's not near as intuitive as an overloaded constructor. Any thoughts on improving this?

\$\endgroup\$
8
\$\begingroup\$

Given that php allows optional parameters and doesn't require type checking of parameters that are passed in, you can sort of "fake" an overloaded constructor.

something like this:

class CommentPanel extends Panel {
    public function __construct($text_or_comment, $username=null, $timestamp=null) {
        if (is_string($text_or_comment) {
            $this->textConstructor($text_or_comment, $username, $timestamp);
        }
        else { // assume that it's a comment since it's not a string ... there are better ways to handle this though
            $this->commentConstructor($text_or_comment);
        }
    }

    private function textConstructor($text, username, $timestampe) { /* . . . */ }
    private function commentConstructor(Comment $comment) { /* . . . */ }
}

This method will allow for a more consistent API and one that is perhaps more familiar to Java and C++ developers.

Also, I'm not positive which version of PHP you're targeting, but I believe in the current version, uses __construct instead of the class name as the constructor. I'm not sure if this is preferred but the documentation does say that it checks for __construct first and then the class name style constructor, so I would guess that using __construct() instead of CommentPanel() would reduce runtime ever so slightly. I'm not 100% sure on that though, that's just my understanding. Please correct me if I'm wrong :)

\$\endgroup\$
  • 5
    \$\begingroup\$ It is in fact preferred to use __construct() instead class name for constructor. The latter is deprecated, and can cause problems in name resolution when working with PHP 5.3 namespaces. \$\endgroup\$ – Mchl Feb 1 '11 at 7:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.