10

I was reading this page - http://deaduseful.com/blog/posts/50-php-optimisation-tips-revisited

And one of the recommendations was to avoid using Magic Methods, cited from a Zend Performance PDF which gives no reason for its recommendation to avoid them.

After some Google searching (and winding up here to an unrelated question) I wondered if anyone had any reccomendations on that front?

I use __get() alot in my code, usually to save variables that I don't always use e.g.

I may have a table with name, desc, category_id, time_added

My get would look something like this:

public function __get($name) {
    switch($name) {
        case 'name':
        case 'desc':
        case 'category':
        case 'time_added':
            $result = do_mysql_query();
            $this->name = $result['name'];
            $this->desc = $result['desc'];
            $this->category = $result['category'];
            $this->time_added = $result['time_added'];
            return $this->{$name};
        break;
        default:
            throw Exception("Attempted to access non existant or private property - ".$name);
    }
}

This seems like a great way to do things as I only ever get something from the database if it's needed and I can refence things like $article->time_added rather than fiddling around with arrays.

Would this be considered bad practice and an extra load on the server?

Often I will extend classes with magic methods and do something like this if the child class doesn't match something in a get.

public function __get($name) {
    switch($name) {
        case 'name':
        case 'desc':
        case 'category':
        case 'time_added':
            $result = do_mysql_query();
            $this->name = $result['name'];
            $this->desc = $result['desc'];
            $this->category = $result['category'];
            $this->time_added = $result['time_added'];
            return $this->{$name};
        break;
        default:
            return parent::__get($name);
    }
}

Would this be bad practice and bad for performance? The maximum number of levels I have when extending magic methods is three.

SamT
  • 10,374
  • 2
  • 31
  • 39
Rob
  • 143
  • 1
  • 6
  • possible duplicate of [__get/__set/__call performance questions with PHP](http://stackoverflow.com/questions/3330852/get-set-call-performance-questions-with-php) – Gordon Sep 03 '10 at 10:21

3 Answers3

17

It's true, they are slower... but the difference is so tiny that speed vs code is a factor. Is it worth worrying about the difference for quicker development and maintenance?

See magic benchmarks for stats

Jorge Y. C. Rodriguez
  • 3,394
  • 5
  • 38
  • 61
Ashley
  • 5,939
  • 9
  • 39
  • 82
  • 19
    +1: You can't overvalue that sentiment. Remember, `Premature Optimization Is The Root Of All Evil`... If you spend all of your time worrying about the tiny speed differences, you'll never get anything done. Build it the way that works for you, and then **if** you have problems, refactor from there. But the biggest performance improvement that you can make is the transition from a non-working state to a working one. Everything else pales in comparison... – ircmaxell Sep 03 '10 at 10:24
  • 1
    Cheers the link is really helpful and your point is very true, it's very difficult not to get caught up in wanting prefect code and never actually releasing any of it :D – Rob Sep 03 '10 at 10:41
  • 4
    IMHO maintainable code is WELL more important than high performance code. Think about it. It's cheaper to throw more hardware at a problem than it is throwing more developers at it. That's one reason that PHP is so popular... Now, there's always a trade-off, so I'm not recommending ignoring performance, but don't try to micro-optimize if you don't know if a problem exists... – ircmaxell Sep 03 '10 at 10:58
  • @ircmaxell, what's a non-working state and what's a working state? – datasn.io Nov 18 '14 at 01:33
  • 1
    @kavoir.com "non working" means the software doesn't work. And working means it works. Simple as that. – ircmaxell Nov 18 '14 at 15:42
  • Perhaps this is obvious, but I think the benchmarks article is misleading. It compares the performance of functions with only one statement in them and deduces that magic methods are 3x slower. Let's assume naively that each function call and statement has a cost of 1, and magic methods have a cost of 2. Then, if you had a 10-statement-long function, the cost of the function is 11 without magic, and 13 with magic, making the magic only 1.2 times slower. This is probably more realistic, given the way people use magic methods to delegate. – Chris Middleton Mar 01 '15 at 03:20
1

Consider using array accessors.

class Record implements ArrayAccess {

    /**
     * @see ArrayAccess::offsetExists()
     *
     * @param offset $offset
     */
    public function offsetExists($offset) {

    }

    /**
     * @see ArrayAccess::offsetGet()
     *
     * @param offset $offset
     */
    public function offsetGet($offset) {
        //fetch and cache $result

        return $result[$offset];
    }

    /**
     * @see ArrayAccess::offsetSet()
     *
     * @param offset $offset
     * @param value $value
     */
    public function offsetSet($offset, $value) {

    }

    /**
     * @see ArrayAccess::offsetUnset()
     *
     * @param offset $offset
     */
    public function offsetUnset($offset) {

    }
aularon
  • 11,042
  • 3
  • 36
  • 41
  • 2
    And that's different how? You're just swapping four magic methods for four other magic methods... – ircmaxell Sep 03 '10 at 10:26
  • @ircmaxell Interface methods are not magic methods. Though I cannot backup with numbers, I claim these will run faster than relying on interceptors – Gordon Sep 03 '10 at 10:43
  • @Gordon: It's slower, check the link in the above answer. And yes, while it's not a "magic method" in the strict sense, it is magic in the sense that the interface enables magic-like functionality (the ability to use core functions and language constructs on the object)... – ircmaxell Sep 03 '10 at 10:55
  • @ircmaxell if you put it this way, then yes, that's a good point. – Gordon Sep 03 '10 at 11:17
1

I did some tests with PHP magic methods and native get/set operations (on a public property)

The results:

Magic methods are much slower than native access. BUT access time is still so small, that it will not make a difference in 99.9% of all cases.

Even if you do 1 Million magic method accesses within one request, it still only takes about 0.1 second...


"Read only" means access via magic methods. The image shows PHP 5.5.9 and PHP 7.0 results.

benchmark results

Here is the benchmark script: https://github.com/stracker-phil/php-benchmark/blob/master/benchmark.php

Philipp
  • 10,240
  • 8
  • 59
  • 71