Cast the Current Object ($This) to a Descendent Class

Cast the current object ($this) to a descendent class

You can, as described in other answers, do it with nasty black magic PECL extensions.

Though, you seriously don't want it. Any problem you want to solve in OOP there's an OOP-compliant way to do it.

Runtime type hierarchy modifications are not OOP-compliant (in fact, this is consciously avoided). There are design patterns that should fit what you want.

Please, tell us why do you want that, I'm sure there must be better ways to do it ;)

php: casting a class to its descendant?

Update

I would suggest looking into traits. Using traits will allow you to reuse code kept in smaller, more manageable components yet still inject their functionality into multiple classes (and have a single class have the capability to use multiple traits). An example I can come up with sorta-modelled on your example:

trait FightingTrait {
protected $weapon;

public function fireWeapon()
{
$this->weapon->fire();
}
}

trait NavigatingTrait {
public function moveTo($location){ /* Implementation */ }

public function eta(){ /* Implementation */ }
}

class Player
{
use FightingTrait, NavigatingTrait;
}

If you happen to have other things that may need to fire or move, you could take advantage of these traits there, too:

class Vehicle {
use FightingTrait, NavigatingTrait;
}

Previous

I don't think you want to do this. At first glance I believe this is a fundamental violation of the Liskov Substitution Principle. Very generally:

If S is a subtype of T, then objects of T may be replaced with objects of Type S.

It does not go both ways: you cannot replace S with T, because S can have added functionality that is not available on T. You have a concrete Player object (T) and you are attempting to force that object to be of one of your subtypes (S), and this is not how inheritance is supposed to work. A Fighter is a Player, but a Player is not necessarily a Fighter. It could also be a Navigator, or any other potential subtype you may want in the future.

If you want to maintain this inheritance chain (Fighter > Player, Navigator > Player), then I would suggest instead designing it a bit differently. Make Player an abstract class, because you want to use it to group functionality that is shared across all of your different base types. Should all of your different player types have the ability to MoveTo() or Fire()? Then it belongs in the Player class. If Navigators can do something different that Fighters cannot (and vice versa), then that logic belongs in the subtype and not in the shared parent.

Note that in this case Player is abstract and you would never actually instantiate an object of type Player. You only want to have a single instance, which is fine, but make that Player instance one of the concrete base classes (e.g. Fighter or Navigator) because those types are a Player.

How can I copy an object of another class?

try this, Once you instantiate a object, you can't change the class (or other implementation details)

You can simulate it like so:

<?php

class Test
{
private $id;
private $name;
private $age;
private $number;

public function getId() {
return $this->id;
}

public function setId($id) {
$this->id = $id;
return $this;
}

public function getName() {
return $this->name;
}

public function setName($name) {
$this->name = $name;
return $this;
}

public function getAge() {
return $this->age;
}

public function setAge($age) {
$this->age = $age;
return $this;
}

public function getNumber() {
return $this->number;
}

public function setNumber($number) {
$this->number = $number;
return $this;
}

public function toArray()
{
return get_object_vars($this);
}

}

class TestCopy extends Test
{
public $fakeAttribute;
}

function getTestCopy($object)
{
$copy = new TestCopy();

foreach($object->toArray() as $key => $value) {
if(method_exists($copy, 'set'.ucfirst($key))) {
$copy->{'set'.ucfirst($key)}($value);
}
}

return $copy;
}

$object = new Test();
$object->setId(1);
$object->setName('Tom');
$object->setAge(20);
$object->setNumber(10);

$copy = getTestCopy($object);
$copy->fakeAttribute = 'fake value';

echo "<pre>";
print_r($object->toArray());
print_r($copy->toArray());

output :

Array
(
[id] => 1
[name] => Tom
[age] => 20
[number] => 10
)
Array
(
[fakeAttribute] => fake value
[id] => 1
[name] => Tom
[age] => 20
[number] => 10
)

Type casting for user defined objects

There is no need to type cast in php.


Edit: Since this topic seems to cause some confusion, I thought I'd elaborate a little.

In languages such as Java, there are two things that may carry type. The compiler has a notion about type, and the run time has another idea about types. The compilers types are tied to variables, whereas the run time engine tracks the type of values (Which are assigned to variables). The variable types are known at compile time, whereas the value types are only known at run time.

If a piece of input code violates the compilers type system, the compiler will barf and halt compilation. In other words, it's impossible to compile a piece of code that violates the static type system. This catches a certain class of errors. For example, take the following piece of (simplified) Java code:

class Alpha {}

class Beta extends Alpha {
public void sayHello() {
System.out.println("Hello");
}
}

If we now did this:

Alpha a = new Beta();

we would be fine, since Beta is a subclass of Alpha, and therefore a valid value for the variable a of type Alpha. However, if we proceed to do:

a.sayHello();

The compiler would give an error, since the method sayHello isn't a valid method for Alpha - Regardless that we know that a is actually a Beta.

Enter type casting:

((Beta) a).sayHello();

Here we tell the compiler that the variable a should - in this case - be treated as a Beta. This is known as type casting. This loophole is very useful, because it allows polymorphism in the language, but obviously it is also a back door for all sorts of violations of the type system. In order to maintain some type safety, there are therefore some restrictions; You can only cast to types that are related. Eg. up or down a hierarchy. In other words, you wouldn't be able to cast to a completely unrelated class Charlie.

It's important to note that all this happens in the compiler - That is, it happens before the code even runs. Java can still get in to run time type errors. For example, if you did this:

class Alpha {}

class Beta extends Alpha {
public void sayHello() {
System.out.println("Hello");
}
}

class Charlie extends Alpha {}

Alpha a = new Charlie();
((Beta) a).sayHello();

The above code is valid for the compiler, but at run time, you'll get an exception, since the cast from Beta to Charlie is incompatible.

Meanwhile, back at the PHP-farm.

The following is valid to the PHP-compiler - It'll happily turn this into executable byte code, but you'll get a run time error:

class Alpha {}

class Beta extends Alpha {
function sayHello() {
print "Hello";
}
}
$a = new Alpha();
$a->sayHello();

This is because PHP variables don't have type. The compiler has no idea about what run time types are valid for a variable, so it doesn't try to enforce it. You don't specify the type explicitly as in Java either. There are type hints, yes, but these are simply run time contracts. The following is still valid:

// reuse the classes from above
function tellToSayHello(Alpha $a) {
$a->sayHello();
}
tellToSayHello(new Beta());

Even though PHP variables don't have types, the values still do. A particular interesting aspect of PHP, is that it is possible to change the type of a value. For example:

// The variable $foo holds a value with the type of string
$foo = "42";
echo gettype($foo); // Yields "string"
// Here we change the type from string -> integer
settype($foo, "integer");
echo gettype($foo); // Yields "integer"

This feature some times confused with type casting, but that is a misnomer. The type is still a property of the value, and the type-change happens in runtime - not at compile time.

The ability to change type is also quite limited in PHP. It is only possible to change type between simple types - not objects. Thus, it isn't possible to change the type from one class to another. You can create a new object and copy the state, but changing the type isn't possible. PHP is a bit of an outsider in this respect; Other similar languages treat classes as a much more dynamic concept than PHP does.

Another similar feature of PHP is that you can clone a value as a new type, like this:

// The variable $foo holds a value with the type of string
$foo = "42";
echo gettype($foo); // Yields "string"
// Here we change the type from string -> integer
$bar = (integer) $foo;
echo gettype($bar); // Yields "integer"

Syntactically this looks a lot like how a typecast is written in statically typed languages. It's therefore also often confused with type casting, even though it is still a runtime type-conversion.

To summarise: Type casting is an operation that changes the type of a variable (not the value). Since variables are without type in PHP, it is not only impossible to do, but a nonsensical thing to ask in the first place.

Changing the class of a Perl object to a subclass

Changing the type of an object is very easy in Perl, even after it has been created (easy enough to get yourself in big trouble).

$car = Vehicle::Factory->new( ... );
... stuff happens to $car ...

# Oh! Now I have decided that $car should be a Vehicle::RustBucket::Fiat
bless $car, 'Vehicle::RustBucket::Fiat';


Related Topics



Leave a reply



Submit