0

When using complex/non-primitive/reference data types as method parameters in Java, a reference to the object is passed to the method:

public class Test {

    public static void main(String[] args) {
        String[] array = {"a", "b", "c", "d", "e"};

        System.out.println(Arrays.toString(array)); // [a, b, c, d, e]
        reverseArray(array);
        System.out.println(Arrays.toString(array)); // [e, d, c, b, a]
    }

    private static void reverseArray(String[] array) {
        int startIndex = 0;
        int endIndex = array.length - 1;
        String tmp;
        while (endIndex > startIndex) {
            tmp = array[endIndex];
            array[endIndex] = array[startIndex];
            array[startIndex] = tmp;
            endIndex--;
            startIndex++;
        }
    }
}

In contrast PHP seems to "copy" method parameters:

<?php

Test::main();

class Test {
    
    public static function main() {
        $array = ["a", "b", "c", "d", "e"];
        
        print_r($array); // [a, b, c, d, e]
        self::reverseArray($array);
        print_r($array); // [a, b, c, d, e]
    }
    
    private static function reverseArray($array) {
        $startIndex = 0;
        $endIndex = count($array) - 1;
        $tmp;
        while ($endIndex > $startIndex) {
            $tmp = $array[$endIndex];
            $array[$endIndex] = $array[$startIndex];
            $array[$startIndex] = $tmp;
            $endIndex--;
            $startIndex++;
        }
    }
}

Only when adding & to the method parameter, PHP will pass a reference to the object:

<?php

Test::main();

class Test {
    
    public static function main() {
        $array = ["a", "b", "c", "d", "e"];
        
        print_r($array);  // [a, b, c, d, e]
        self::reverseArray($array);
        print_r($array);  // [e, d, c, b, a]
    }
    
    private static function reverseArray(&$array) {
        $startIndex = 0;
        $endIndex = count($array) - 1;
        $tmp;
        while ($endIndex > $startIndex) {
            $tmp = $array[$endIndex];
            $array[$endIndex] = $array[$startIndex];
            $array[$startIndex] = $tmp;
            $endIndex--;
            $startIndex++;
        }
    }
}

If I want to simulate PHP's "default" behaviour (without the &) in Java, I have to copy the array:

public class Test {

    public static void main(String[] args) {
        String[] array = {"a", "b", "c", "d", "e"};

        System.out.println(Arrays.toString(array)); // [a, b, c, d, e]
        reverseArray(Arrays.copyOf(array, array.length));
        System.out.println(Arrays.toString(array)); // [a, b, c, d, e]
    }

    private static void reverseArray(String[] array) {
        int startIndex = 0;
        int endIndex = array.length - 1;
        String tmp;
        while (endIndex > startIndex) {
            tmp = array[endIndex];
            array[endIndex] = array[startIndex];
            array[startIndex] = tmp;
            endIndex--;
            startIndex++;
        }
    }
}

My questions are now:

  1. Does PHP copy every method parameter when I do not specifically use references? If yes, is this not very expensive (in regards of computation time and space)?
  2. Why are Java and PHP using different "default" methods of passing method parameters? Is there a clear advantage to one way or another?
hammerl
  • 11
  • 2

3 Answers3

1

1). No PHP does not copy every parameter. Instead, it counts number of references, and copies the object only when you're modifying it.

<?php
  $a = array('Hello');
  debug_zval_dump($a); // array(1) refcount(3){   [0]=>  string(5) "Hello" refcount(1) }

  $b = $a; // copy reference, not the content

  debug_zval_dump($a); // array(1) refcount(4){  [0]=>  string(5) "Hello" refcount(1) }
  // Note refcount increased;

  $b[] = 'World'; // modifying the array causes the object to copy

  debug_zval_dump($a); // array(1) refcount(3){  [0]=>  string(5) "Hello" refcount(2) }
  // Note refcount decreased back, but "Hello" refcount increased, because now it is used in two arrays

I.e. passing strings, arrays etc. into a function, if it is not modified inside, will be the same effective as passing a reference in java.

  1. Note, arrays in Java are objects, while in php they are the separate type. If you create real objects in php, they are always passed by reference
<?php
  function doit($o) { // Passing as is, without &
    $o->x = 'Good bye';
  }

  $a = new \stdClass();
  $a->x = 'Hello';

  doit($a); // Objects are always work as a reference

  print $a->x; // Good bye;
AterLux
  • 4,566
  • 2
  • 10
  • 13
1

The PHP side is well explained by @AterLux's answer.

But, some insights on your followup question:

Why are Java and PHP using different "default" methods of passing method parameters? Is there a clear advantage to one way or another?

'Simple' is a term that is in the eye of the beholder. For example, take the approach to identifier naming (the name of a method). In java, identifiers are precisely what they are (so, case sensitive, for example). In PHP, they are case insensitive.

In one 'mindset', PHP's choice is 'simpler': As a script writer I don't have to worry about copying casing. There are SO questions about 'why does this not work', and the problem is that they named their method 'checkFoo' and are calling 'checkfoo'.

In another 'mindset', Java's choice is 'simpler': In the turkish locale, there is a difference between the dotted i and the dotless i. So, in turkish, "i".toUpperCase() is actually "İ", and "I".toLowerCase() is actually "ı". The way PHP does the 'case insensitive' thing is by internally uppercasing everything and tossing that into a big hashmap (I'm oversimplifying a bit), leading to the rather well known issue that, in turkish locale, most PHP scripts just straight up do not work, as mixing up 'i' and 'I' will now no longer translate to the same uppercase sequence of characters. In that way, the PHP solution is much more complicated than the java one. See? It is in the eye of beholder.

But there is a trend here: If you fully grok exactly how it all works under the hood, java is, almost always, a lot simpler than PHP is. If you are merely just sort of doing the first thing that comes to mind, PHP tends to be 'simpler'. PHP tries to 'help' you, second guess, attempt to divinate your intentions and act accordingly. For example, and let's use as example that other 'tries to guess' language: javascript, 1 is 'truthy' - if used as a boolean, javascript looks in its crystal ball and will guess you intend for that to be true. Java doesn't do that. true is true, and that's it. if (1) {} in java doesn't even compile.

In that vein, java is 'simple' in the java way: primitives are themselves, and all non-primitives are a reference. These references are passed by value. There is no C-style & or * - that's what you get.

PHP is 'simple' in the PHP way: It tries to peddle the notion that everything is pass-by-value, and to make that work without being incredibly inefficient, arrays are passed wrapped up, so that no actual copy is needed, but IF the function you pass the array to changes it, THEN it makes a copy. Except that's too tricky for objects, so those ARE always passed by reference.

I'd say PHP's haphazard approach to consistency leads to an incredibly inconsistent language.

It also means java tends to be a bit bizarre at a casual glance, because often 'making sense once you fully understand how it all works' is at odds with 'does what you intended as you flail away without understanding much'. However, given that we still haven't invented a language that can work around idiotic programmers, as a rule I'd advocate for the java school of thought on what 'simple' means, and not the PHP school of thought. Therefore, I would answer your question with:

Java tries to make the model simple, PHP tries to make the experience simple, which explains the difference. There is a clear advantage to the way java does it, however.

rzwitserloot
  • 85,357
  • 5
  • 51
  • 72
0

Java and PHP roughly have the very same behaviour on this regard: objects are passed by reference, everything else is passed by value. The key difference is that arrays are objects in Java but not in PHP. Yes, this is an oversimplification, but it should be good enough as thumb rule.

For what it's worth, PHP used to behave differently before 2004. In PHP/4 and earlier everything was passed by value unless you used the & operator. Perhaps that explains that references to this (no pun intended) are unfortunately scattered in several places but typically in OOP chapters:

  • Classes and Objects (PHP/5+):

    PHP treats objects in the same way as references or handles, meaning that each variable contains an object reference rather than a copy of the entire object.

  • Objects and references:

    A PHP reference is an alias, which allows two different variables to write to the same value. As of PHP 5, an object variable doesn't contain the object itself as value anymore. It only contains an object identifier which allows object accessors to find the actual object. When an object is sent by argument, returned or assigned to another variable, the different variables are not aliases: they hold a copy of the identifier, which points to the same object.

  • Passing by Reference:

    You can pass a variable by reference to a function so the function can modify the variable.

    (No reference to objects)

The most complete overview is probably References Explained. The difference between alias and reference is pretty subtle but, IMHO, you don't really need to master it for most use cases.

Álvaro González
  • 142,137
  • 41
  • 261
  • 360