How to Cast Objects in PHP

PHP Cast to my class

As I know, in PHP you can only cast to some types:

(int), (integer) - cast to integer
(bool), (boolean) - cast to boolean
(float), (double), (real) - cast to float
(string) - cast to string
(binary) - cast to binary string (PHP 6)
(array) - cast to array
(object) - cast to object
(unset) - cast to NULL (PHP 5) (depracted in PHP 7.2) (removed in 8.0)

(see Type Casting)

Instead you could use instanceof to check of specific type:

if($yourvar instanceof YourClass) {
//DO something
} else {
throw new Exception('Var is not of type YourClass');
}

EDIT

As mentioned by Szabolcs Páll in his answer, it is also possible to declare a return type or parameter type, but in that cases an exception (TypeError) will be throwen, if the type does not match.

function test(): string
{
return 'test';
}

function test(string $test){
return "test" . $test;
}

Since PHP 7.2 it is also possible to make the types nullable by adding ? in front of them:

function test(): ?string
{
return null;
}

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.

How to cast type by the object that is to be assigned?

$copy = $value;
if(settype($copy, gettype($object)))
$object = $copy;

foreach to cast objects in php

I finally find where it didn't work, finally the problem is not really related to the question here, but since it was quite surprising I decide to answer myself here and maybe you can help me to explain what i just experienced because i am not sure to understand why.

I had two classes,

class Foo {
...
}

class Bar {

/** @var Foo $foos */
$foos = array();

public function set_foos ($foos) { $this->foos = $foos; }
public function get_foos () { return $this->foos; }
}

in Linux, writing

$foos = [new Foo(), new Foo()];
$bar = new Bar(); $bar->set_foos($foos);

foreach ($bar->get_foos as &$foo) {
$foo = 1;
}

didn't work, the Foo Objects didn't get changed to 1. To change them to 1 I had to add a function to Bar class,

class Bar {

...

public function serialize () {
foreach($this->foos as &$foo) {
$foo = 1; // works
}
}
}

can someone explain why ?

Is there a way to cast an array to (object) as a property of class/trait?

Quoting from the PHP Docs:

They [object properties] are defined by using one of the keywords public, protected, or private, followed by a normal variable declaration. This declaration may include an initialization, but this initialization must be a constant value -- that is, it must be able to be evaluated at compile time and must not depend on run-time information in order to be evaluated.

(my emphasis)

And

public $obj = (object) ['a','b','c'];

is dependent on run-time information, namely run-time casting of array to object

The way to get round this is to assign the value in the constructor

Convert a PHP object to an associative array

Just typecast it

$array = (array) $yourObject;

From Arrays:

If an object is converted to an array, the result is an array whose elements are the object's properties. The keys are the member variable names, with a few notable exceptions: integer properties are unaccessible; private variables have the class name prepended to the variable name; protected variables have a '*' prepended to the variable name. These prepended values have null bytes on either side.

Example: Simple Object

$object = new StdClass;
$object->foo = 1;
$object->bar = 2;

var_dump( (array) $object );

Output:

array(2) {
'foo' => int(1)
'bar' => int(2)
}

Example: Complex Object

class Foo
{
private $foo;
protected $bar;
public $baz;

public function __construct()
{
$this->foo = 1;
$this->bar = 2;
$this->baz = new StdClass;
}
}

var_dump( (array) new Foo );

Output (with \0s edited in for clarity):

array(3) {
'\0Foo\0foo' => int(1)
'\0*\0bar' => int(2)
'baz' => class stdClass#2 (0) {}
}

Output with var_export instead of var_dump:

array (
'' . "\0" . 'Foo' . "\0" . 'foo' => 1,
'' . "\0" . '*' . "\0" . 'bar' => 2,
'baz' =>
stdClass::__set_state(array(
)),
)

Typecasting this way will not do deep casting of the object graph and you need to apply the null bytes (as explained in the manual quote) to access any non-public attributes. So this works best when casting StdClass objects or objects with only public properties. For quick and dirty (what you asked for) it's fine.

Also see this in-depth blog post:

  • Fast PHP Object to Array conversion

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 ;)



Related Topics



Leave a reply



Submit