10

I started of writing a wrapper class for a pre-defined php package. Here are the classes:

class phpclass1
    :: ping()
    :: __construct(array $options)
    :: clear() 
    :: addDoc(phpclass2 $string)

...

class phpclass2 
    :: __construct()
    :: update()
...

Here are the wrapper classes that I wrote for the above 2 classes:

class wrapper1 {
    private $conn;

    public function __construct(phpclass1 $object) {
        $this->conn = $object;
    }

    public function add(wrapper2 $document) {
        return $this->conn->addDoc($document);
    }
}

class wrapper2 extends phpclass2 {
    private $doc;
    public function __construct() {
        $this->doc = new phpclass2();
    }    
}

Here's how I'm using them:
$options = array (...);
$object = new phpclass1($options);
$conn = new wrapper1($object);
$doc = new wrapper2();
....
....
$conn->add($doc);

Everything was working until I used the add function. It gives an error: Argument 1 passed to phpclass1::addDoc() must be an instance of phpclass2, instance of wrapper2 given

What am I missing? I've tried out many things, but completely lost here.

14
  • 8
    The argument to phpclass1::addDoc() is type-hinted as a phpclass2, and you are passing it $document, which is a wrapper2. Unless wrapper2 extends phpclass2, the type hint will fail. Commented Jul 24, 2013 at 23:53
  • @MichaelBerkowski: I tried that, but there was some error. (I guess the php package I'm using may not entertain such duplication/cloning of instances). So I was wondering if there could be some other way. Commented Jul 25, 2013 at 0:02
  • 2
    We would need to see what the error is. As long as you don't attempt to override final or private methods, you ought to be able to extend the class save for some potentially exotic case. Commented Jul 25, 2013 at 0:05
  • 1
    Biggest problem with your question (IMHO) is that you don't provide the code. Another big problem I see is that you do not clarify why in concrete you've got that question. E.g. why are you asking this? What is the concrete reason? What is the concrete problem you're trying to solve? Commented Aug 11, 2013 at 6:01
  • 1
    And what is the pre-defined PHP package you wrote about in the question but didn't specify further? And you might want to read about the Proxy Design Pattern probably. Commented Aug 11, 2013 at 6:10

4 Answers 4

2

You have defined

class phpclass1 :: addDoc(phpclass2 $string)

This method expects the argument to be an object of phpclass2, but you are passing

return $this->conn->addDoc($document);

through

$conn->add($doc);

and $doc is an object of wrapper2 not phpclass2

To fix add a new public method

wrapper2::getDoc()

public function add(wrapper2 $document) {
    return $this->conn->addDoc($document->getDoc());
}
Sign up to request clarification or add additional context in comments.

3 Comments

He is correct, you are passing the wrong type, you can also solve this by making wrapper2 extend phpclass2. Also see the Proxy Pattern
@NickyDeMaeyer: I've edited my code to extend the wrapper2 class to phpclass2. But, still it gives an error: phpclass1::addDoc(): wrapper2 is not valid.
You are still passing the wrong object to $this->conn->addDoc(). You are passing an object of wrapper2 instead if an object of phpclass2. Solution with adding a new public method is so simple, why won't you implement it?
2
+50

THE PROBLEM

You are type hinting a wrapper1 method to accept type of wrapper2 all well and good. Inside the wrapper1 method you declare

public function add(wrapper2 $document) {
        return $this->conn->addDoc($document);
    }

where $conn is defined as a phpclass1 instance. The problem arises as you call

return $this->conn->addDoc($document);

which is expecting a type of phpclass2but $document is in fact a type of wrapper2 as we take it you cannot edit either phpclass1 OR phpclass2 you will need to modify your wrapper classes.

The Solutions

Solution 1

either change wrapper2 to be

class wrapper2 {
    private $doc;
    public function __construct() {
        $this->doc = new phpclass2();
    }
    public function GetDoc()
    {
      return $this->doc;
    }
}

and use as follows

$conn->add($doc->GetDoc());

Solution 2

change the signature of $doc; inside of wrapper2 to public and use as follows

$conn->add($doc->doc);

for more information on typehinting in php have a look at the documentation page for it php type hinting

one other thing to consider is do you need/want to type hint, not putting up an argument for/against as its already been debated at length, just a question that you may want to ask.

If the answer is yes, you may want to read the following link which talks about good ways and reasons to use type hinting

I hope this helps

4 Comments

Thanks a lot. It works, though throws an error for destruct: Warning: phpclass2::__destruct():
On a completely different note, is there any other way of implementing wrapper classes?
depending on your opinions on them you could of used interfaces in conjunction with your wrapper classes, but as far as I'm aware I would of done much the same as what you have done. As for the destruct warning what is the complete error for it?
as has been pointed out by the other answers you could of also used inheritance by creating sub classes of phpclass1 and phpclass2 although that probably wouldn't make much sense in this instance.
0

Your phpclass1::addDoc is type hinted to take only an object of phpclass2. Your wrapper1::add method takes an object of type wrapper2 and then passes it to the phpclass1::addDoc Based on your classes this is inconsistent as wrapper2 is not an instance of phpclass2.

You need to change your typehint or allow the wrapper2 class to provide the phpclass2 object that it is wrapping or extending the wrapper2 so that it is an instance of phpclass2

1 Comment

I've edited my code to extend the wrapper2 class to phpclass2. But, still it gives an error: phpclass1::addDoc(): wrapper2 is not valid.
0

Change public function add(wrapper2 $document) to public function add($document) the type hinting is the issue.

Comments

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.