A polymorphism problem - Part 1

So I've recently moved back to South Africa from London and I've been looking for work. My core roles over the years have been as an IVR (Interactive Voice Response) Developer. Now days, these systems are all voice XML and you get to work in Java, but the companies I've been working for all use proprietary hardware and proprietary languages, which is all fine and dandy for IVR, but doesn't translate well into transferable skills for the developer. However, if you need anything done outside of the IVR environment, you end up working in other languages, so I've ended up with some working experience in PHP/C/C++/Java/C#/SQL/etc.

Anyway, as I was saying, I'm back from London, looking for work in Cape Town. I've looking to Focus in either PHP or C# as its the two languages I enjoy the most and find I work well in the environments. So I went to a job interview for a PHP web developer position and the interview goes well and they send me a test. In the test, it asked you to use concepts like arrays, loops, objects, etc. Now, I’ve worked with objects before and got the basic concepts down (I think), but I keep running into things I don’t know.

So I’ve decided to take the mysqli objects that are used to connect and communicate with a mySQL database and extend them with my own class that simply calls the old object, but throws exceptions instead of returning errors, I’ll refer them as wrappers from now. It’s not going to change the world or anything, but it gave me a chance to learn some things about objects in PHP, as I hadn’t done much of it.

I had created a wrapper for the mysqli and mysqli_stmt objects. The problem I came into when I tried to extend the to create my own prepare statement function. In the function I called mysqli::prepare function, which returns a mysqli_stmt object. Of course, I don’t want a mysqli_stmt object, I want my wrapper statement object. I thought I could just cast it to my wrapper statement object.

I thought wrong.

Here’s a basic version of the code I was trying to use:

<?php
 
class animal
{
	public $name;
 
	public function __construct($inName)
	{
		$this->name = $inName;
	}
}
 
class cat extends animal
{
	public function setName($inName)
	{
		$this->name = $inName;
	}
}
 
class god
{
	public function createAnimal($animalName)
	{
		return new Animal($animalName);
	}
}
 
 
$tikigod = new god();
$cat = new cat(“Not a cat”);
 
$cat = $tikigod->createAnimal("Animal");
$cat->setName("Kitty");
 
echo "Look a ".$cat->name;
 
?>

This doesn’t work. You’ll get a compile error saying “Fatal error: Call to undefined method animal::setName()”. I’ve tried different approaches, like casting what createAnimal() returns to my wrapper object, but nothing works. Turns out, you can’t assign a base class to a derived class. You can however return a derived class to a base class and still be able to access the derived class functions and variables. However, I still had a problem, I wanted to use my wrapper classes together.

Due to time constraints on the test, I couldn’t spend too much time trying to work it out, so I sent the test off without the second wrapper class. The problem has still been bugging me though, so I’ve done some reading up and I think I’ve come up with a solution. It doesn’t work exactly how I wanted, but it gets the job done.

Here's how I think I could get the classes working together in a basic way:

<?php
 
class animal
{
	public $name;
 
	public function __construct($inName)
	{
		$this->name = $inName;
	}
}
 
class cat extends animal
{
	public function __construct(animal $inObj)
	{
		$this->name = $inObj->name;
	}
 
	public function setName($inName)
	{
		$this->name = $inName;
	}
}
 
class god
{
	public function createAnimal($animalName)
	{
		return new Animal($animalName);
	}
}
 
 
$tikigod = new god("tikigod");
 
$cat = new cat($tikigod->createAnimal("Animal"));
$cat->setName("Kitty");
 
echo "Look a ".$cat->name;
 
?>

What it basically boils down to, is you simply take the object that you’re extending as a input argument for your extended class constructor. Once you’ve done that you simply assign all the values that’s in the base class to the values of the extended class in the constructor.

Now in theory this is all fine and good, but the problem is, it still doesn't work 100% the way one would want. It works fine for our limited example and will probably work when you've written the original class you're extending and the new derived class, but in the case where I'm trying to extend the mysqli classes, it doesn't help me.

I'll cover extending the mysqli class in part 2 and how I finally got it working.

Synack