views:

73

answers:

5

I have a simple 'dimensions' class containing a width/height property and a constructor to set them.

I have a function (to re-size dimensions) that takes two dimensions objects -- one to be re-sized, and one containing the max size. It should reduce the dimensions in the first parameter such that they 'fit into' the second parameter.

Then it returns the first, newly resized one.

The caller passes the dimensions object in and gets the return value into a different one -- because it has to preserve the original object. But the one that is passed into the function gets modified.

This was surprising since I didn't take it by reference:

private function scale_image_dimensions(Dimensions $dimensions, Dimensions $max_size) {

    if( $dimensions->width > $max_size->width ) {
        $dimensions->height = $dimensions->height / ($dimensions->width / $max_size->width);
        $dimensions->width = $max_size->width;
    }

    if( $dimensions->height > $max_size->height ) {
        $dimensions->width = $dimensions->width / ($dimensions->height / $max_size->height);
        $dimensions->height = $max_size->height;
    }

    return $dimensions;
}

How do I specify that I want the function to make a copy of the objects passed into it, and then return one of them?

update

It seems something else is fishy -- I changed the argument from $dimensions to $adimensions, and put $dimensions = $adimensions at the beginning of the function.

But the caller's variable still gets modified! Does assignment work by reference also? I mean... There's non way to make an assignment operator overload, or a copy constructor so... what do I do? If I want a copy I have to explicitly initialize one every time?

+2  A: 

All objects are, by default, referred to as references. In order to make a copy of the object, you must clone it using the clone keyword.

private function scale_image_dimensions(Dimensions $dimensions, Dimensions $max_size) {
    $old_dimensions = $dimensions;
    $dimensions = clone $dimensions;

    if( $dimensions->width > $max_size->width ) {
        $dimensions->height = $dimensions->height / ($dimensions->width / $max_size->width);
        $dimensions->width = $max_size->width;
    }

    if( $dimensions->height > $max_size->height ) {
        $dimensions->width = $dimensions->width / ($dimensions->height / $max_size->height);
        $dimensions->height = $max_size->height;
    }

    return $dimensions;
}

This keeps PHP from making large amounts of objects, and generally people want objects to be passed by reference anyway.

PHP Classes are not very often used as a 'Data Storage' utility, because arrays often work just as well.

But, if you are coming for another language that does use many classes to store data, I can see that it would be a big problem.

Chacha102
Gotta love when everyone upvotes all the other answers that are the exact same as yours, but not yours!
Chacha102
:) There we go!
Chacha102
I was reading through and commenting, sorry. Haha, it is an awful experience though
Carson Myers
ps. I used a class for the constructor, because the rest of the application is classes, and because I didn't know about this cloning issue.
Carson Myers
+1  A: 

Might the clone keyword be what you're looking for?

$return_dimensions = clone $dimensions;
Adam Benzan
Why yes, I do believe it is!
Carson Myers
+1  A: 

PHP5 automatically handles params as references. You could clone the object using the clone keyword.

$newObject = clone $originalObject;

One thing you should be concerned about is the difference between a full copy and a shallow copy when cloning. By default, clone will only make a shallow copy.

Brad
+1  A: 

The parameters are, in a sense, passed by value, since you can reassign $dimensions without affecting the original.

But object variables are just pointers to the actual object, so you're correct that changing their member variables will affect the original object.

If you want to avoid this, you'll need to clone the objects. PHP has a cloning feature, but keep in mind that it makes shallow copies by default. So if your objects contain other objects, you won't get clones of those; just references to the originals. You may just want to manually create new objects and copy their values yourself.

JW
+3  A: 

Thought many people are totally against cloning, I am all for it.

Edit: Object are assigned by reference and passed by reference as well.

If you need a deep clone of an object, use the clone keyword as in $cloned = clone $dimensions and also define the magic method __clone() in your Dimensions class to ensure that the any object references inside Dimensions are actually cloned as well.

Anurag
I literally lol'd when I found that the first link was an article about biological cloning.
Carson Myers
I'll go with this answer for explaining the difference between 'deep' and 'shallow' clones and describing how to make a deep clone
Carson Myers