5

I have a custom class object in PHP named product:

final class product
{   
    public $id;
    public $Name;
    public $ProductType;
    public $Category;
    public $Description;
    public $ProductCode;
}

When passing an object of this class to my Data Access Layer I need to cast the object passed into a type of the product class so I can speak to the properties within that function. Since type casting in PHP works only with basic types what is the best solution to cast that passed object?

final class productDAL
{
    public function GetItem($id)
    {
        $mySqlConnection = mysql_connect('localhost', 'username', 'password');
        if (!$mySqlConnection) { trigger_error('Cannot connect to MySql Server!'); return; }
        mysql_select_db('databaseName');
        $rs = mysql_query("SELECT * FROM tblproduct WHERE ID='$id';");
        $returnObject = mysql_fetch_object($rs, 'product');
        return $returnObject;
    }

    public function SaveItem($objectToSave, $newProduct = false)
    {
        $productObject = new product();
        $productObject = $objectToSave;

        echo($objectToSave->Name);
        $objectToSave->ID;

    }
}

Right now I am creating a new object cast as a type of product and then setting it equal to the object passed to the function. Is there a better way of accomplishing this task? Am I going about the wrong way?

EDITED FOR CLARITY - ADD FULL PRODCUTDAL CLASS

Jeff
  • 1,742
  • 5
  • 24
  • 39
  • possible duplicate of [Convert/cast an stdClass object to another class](http://stackoverflow.com/questions/3243900/convert-cast-an-stdclass-object-to-another-class) – Gordon Feb 08 '11 at 15:35
  • Oh, maybe what you are aiming for are [interfaces](http://www.php.net/manual/en/language.oop5.interfaces.php)? You can then [type-hint](http://www.php.net/manual/en/language.oop5.typehinting.php) this interface in your function signature, and as such be sure that all object contracted to have these properties (even if the interface is empty). – giraff Feb 08 '11 at 15:52

4 Answers4

9

You don't need to cast the object, you can just use it as if it was a product.

$name = $objectToSave->Name;
Sjoerd
  • 74,049
  • 16
  • 131
  • 175
  • 1
    Hmm... you seem to be correct. Intellisense in NetBeans will not work due to it not being cast properly but it seems this is a real solution. Any pitfalls to operating this way? – Jeff Feb 08 '11 at 15:49
  • 13
    Oh, a great way to trick Intellisense : `if (false) $objectToSave = new product;` . Speeds up development and can be removed afterwards. – giraff Feb 08 '11 at 15:55
  • 2
    I upvoted this answer. But with this answer, no IDE will know that $objectToSave is a Product, having a Name property. Hence, the IDE does not help you. Tricking the IDE with non-production code to get helpful intellisense should be unnecessary. True casting would allow the IDE know the type, and provide better intellisense/autocomplete. – Steve Kennedy Mar 13 '18 at 20:11
1

Type casts in PHP are done like this:

$converted = (type) $from;

Note, that this won't work if the object types are not compatible (if for example $form happens to be a string or object of mismatching type).

But usual solution (called Active Record pattern, present for example in Zend Framework) is to have a base class for a database item called Row. Individual items (for example the class product from your sample) then inherit from this class.

Typical ZF scenario:

$table = new Product_Table();
$product = $table->find($productId); // load the product with $productId from DB
$product->someProperty = $newPropertyValue;
$product->Save(); // UPDATE the database

Which is IMO much better than your solution.

EDIT:

You can't cast between two unrelated objects, it is not possible.

If you want to use the DAL like this, skip the "product" object and go for simple associative array. You can enumerate over its members with foreach, unlike object's properties (you could use reflection, but that's overkill).

My recommendation: Go for the Active Record pattern (it is easy to implement with magic methods). It will save you a lot of trouble.

Matěj Zábský
  • 16,909
  • 15
  • 69
  • 114
  • I've tried this method but it generates an error and renders the page useless. ($productObject = (product)$objectToSave;) I have an error capturing system setup to report errors back but it doesn't allow the page to even load that far. If I'm not mistaken, that type of casting can only be done with certain object, correct? http://php.net/manual/en/language.types.type-juggling.php – Jeff Feb 08 '11 at 15:38
  • What is the type of $objectToSave? – Matěj Zábský Feb 08 '11 at 15:39
  • IMO, type-casting cannot be used for reference-type variables. So even if you cast a product into a row, it still behaves like a product and still has the type "object reference". – giraff Feb 08 '11 at 15:40
  • The type of $objectToSave is the product class I've created. In addition, I'm not using ZF for now. – Jeff Feb 08 '11 at 15:47
  • So is the product class in the first sample same as the one created in the second sample? – Matěj Zábský Feb 08 '11 at 15:52
  • See EDIT for clarity. The product class is used as a data container class and passed to the Data Access Layer for speaking back and forth to the database. – Jeff Feb 08 '11 at 15:55
  • Public object members can be iterated, so there is no need for an assoc array. And you can still use the Iterator interface for non-public properties. Suggesting AR when the OP already made the effort to separate DAL and Business objects seems a bit odd. – Gordon Feb 08 '11 at 16:09
  • Except you can't cast to classes in php. At all. Only casting to 'object' is possible, which will yield an object of the 'stdClass' class. (As of versions up to and including 7.0.) – katrmr Oct 06 '15 at 21:57
1

I´m not sure what you are trying to achieve, but if $objectToSave is already of class product:

  • You can simply call $objectToSave->SaveItem() (assuming SaveItem() is part of the product class) and access it´s properties in the function like $this->Name, etc.;
  • In your code $productObject and $objectToSave will hold a reference to the same object.
jeroen
  • 91,079
  • 21
  • 114
  • 132
0

Currently, you are creating a new Product, then discarding it immediately (as its reference is replaced by $objectToSave.) You will need to copy its properties one by one, I regret.

foreach (get_object_vars($objectToSave) as $key => $value)
{
    $product->$key = $value;
}

(If the properties of $objectToSave are private, you will need to a expose a method to_array() that calls get_object_vars($this).)

giraff
  • 4,601
  • 2
  • 23
  • 35
  • You can just `clone` the object if you want a real copy, but that´s completely unnecessary just to save it in a database... – jeroen Feb 08 '11 at 15:46
  • `clone` wouldn't change the class attached to the properties. – giraff Feb 08 '11 at 15:48