1

Hi all. Been fiddling with an idea about combining setters and getters in PHP. I really don't like magic methods (__get and __set) as they're not very flexible (IMO), but equally bore myself to distraction with set/get methods. Anyhow, having used jQuery for some time, I really liked the non-verbose methods of setting and getting in the client code:

var p = myDiv.html(); //getting
myDiv.html("Hi all"); //setting

So I came up with this as an example:

    public function producers( $producers = null )
    {
        if(func_num_args() > 0){
            $this->_producers = $producers;
            return $this;
        }else{
            return $this->_producers;    
        }
    }

It uses the func_num_args to decide whether to set or get. Looking for some feedback. I realise this may not be unique and tried before and the function does do 2 different things. Is this a valid approach or would it bring down the walls of outrage if I placed it in some client code?

3
Contributors
7
Replies
67
Views
1 Month
Discussion Span
Last Post by diafol
2

Diafol I guess you are referring to plain objects … (every OOP language has that short of thing PHP has PPO or POPO (Plain PHP Objects) , their main concern is to hold data with none or minimum logic in getters and setters. In fact I am using that in PPO many years now especially in Boolean types, here is an example in PHP 7 (no need for func_num_args):

class Something
{
    /**.
     * @var boolean
     */
    private $active = false; 

    public function setActive(bool $active)
    {
        $this->active = $active;
    }

    /**
     * @return boolean
     */
    public function getActive()
    {
        return $this->active;
    }

    public function active($active = null)
    {
        if($active === null)
        {
            return $this->active;
        }
        else if (is_bool($active))
        {
            $this->active = $active; 
            return $this->active;
        }
        else 
        {
            $code = 999;
            throw new Exception("A message",$code);
        }
    }
}

$something = new Something();
$something->setActive(true);
echo $something->getActive() == true ? "IS TRUE </br>" : "IS NOT TRUE </br>";
echo $something->active() == true ? "IS TRUE </br>" : "IS NOT TRUE </br>";
echo $something->active(false) == true ? "IS TRUE </br>" : "IS NOT TRUE </br>";

The triple = there is because PHP can't be real strong typed and for example understands also 0 as false

Edited by jkon

0

In addition: the aim is to be able to chain the methods while setting?

Yes indeed. I was wasting some time (!) creating a discography app and going through the getters and setters for fields was such a pita. So was looking at something like:

$a = new Album;
$a->producers("Mutt Lange")->title("Back In Black")->release(1980);
echo $a->title();

@jkon I follow the logic. And if we pass a var which is null - the object gets instead of sets. But if I pass anything, I'd want it to set (or throw an exception).

2

If implemented, IMO, it should be consistent through all code as jQuery does.

Using mutators and accessors, as described by jkon, can simplify because the naming suggests what to expect: setSomething(), getSomething(). Even if more verbose.

Anyway, I made a small research, this could be defined as dynamic dispatch which can be combined with traits, in the end you could create methods with similar names which are choosen by the reflection library basing on the signature (parameter types).

An example is here:

Here's the source:

Which however does not deal with empty methods, so I made few small changes to __candidateMatch() and to __resolveparameterTypes() which was not handling booleans correctly, now it seems to work fine (pasting outside, because the post is too long):

Here's the test class:

<?php

require 'overloader.php';

class Test {

    use Overloader;

    private $_producers;
    private $_song;
    private $_songs;

    // Producers //

    public function producers_set(string $str)
    {
        $this->_producers = $str;
        return $this;
    }

    public function producers_get()
    {
        if(property_exists($this, '_producers'))
            return $this->_producers;

        return '';
    }

    public function producers_unset(bool $unset)
    {
        $this->_producers = NULL;
        return $this;
    }

    // Song //

    public function song_set(string $str)
    {
        $this->_song = $str;
        return $this;
    }

    public function song_get()
    {
        if(property_exists($this, '_song'))
            return $this->_song;

        return '';
    }

    public function song_unset(bool $unset)
    {
        $this->_song = NULL;
        return $this;
    }

    // Songs //

    public function songs_set(string $str)
    {
        $this->_songs[] = $str;
        return $this;
    }

    public function songs_get()
    {
        if(property_exists($this, '_songs'))
            return implode(', ', $this->_songs);

        return '';
    }

    public function songs_unset(bool $unset)
    {
        $this->_songs = NULL;
        return $this;
    }

    // Debug //

    public function __sleep()
    {
        return ['_producers', '_song'];
    }
}

$t = new Test;
$t->producers('Gogol Bordello')->song('Troubled Friendsz');
print $t->producers() . PHP_EOL;
print $t->song() . PHP_EOL;

$t->song('Start Wearing Purple');
print $t->song() . PHP_EOL;

$t->songs('Wonderlust King');
$t->songs('Sun is On My Side');
print $t->songs() . PHP_EOL;

$t->song(null); # <- does not work
print $t->song() . PHP_EOL;

$t->song(false); # <- this works
print $t->song() . PHP_EOL;

I don't know if I would use it. The issue is that you cannot use NULL for now, I'm using a boolean instead but I don't like it. Maybe with PHP 7.1 instead of writing:

 public function song_unset(bool $unset)
{
    $this->_song = NULL;
    return $this;
}

is possible to rewrite the signature to ?str $str:

 public function song_set(?str $str)
{
    $this->_song = $str;
    return $this;
}

and pass NULL. I don't know. In your approach predicting the result is far easier. My point (wasting time a part! :D) was to test how to keep the logic of the methods separated.

Most important part of this post, the songs :D

Votes + Comments
Outstanding post and effort. Give me some time to process it! Songs :D
Very interesting songs
1

diafol : "I really don't like magic methods (get and set) as they're not very flexible (IMO), but equally bore myself to distraction with set/get methods. "

One of the worst things is writing by hand getters and setters (mutators and accessors). If we are talking about PPO objects (Plain PHP Objects that their main reason to be is to hold data) I have shared a simple JS solution that creates a PHP class with properties , getters and setters using simple naming conversions from the “SHOW CREATE TABLE x” result. That is if you created the tables or are lucky enough to have meaningful field names.

Take a look at the comment in my second post in the thread:
https://www.daniweb.com/programming/web-development/tutorials/500310/object-instantiators-from-data-layer-for-php-oop-applications

Votes + Comments
Forgot all about that thread! Am going through it. May take some time :)
0

Thanks both for your contributions. I am trying to get my head around some of the ideas you've very kindly put together. Have landed some work that can't be ignored - so if I don't reply for a little while...

The codegen script would really speed up my dev, but it still leaves me with all those ghastly accessors and mutators. It's bad trying to write them, but (IMO), it's equally tiresome to scroll through all that stuff.

BTW, I was working on non-7 specific - so selecting by parameter type declaration (e.g. laracast post), could prove a little difficult. But I'm not too bothered. I only use 5 in test platforms (e.g. c9.io), so 7-only is fine.

1

Ok, managed to get my head around various scripts. Thanks again both and sorry for the delay. The reflection class idea got me thinking about a slightly different approach, one that will use child objects. It probably makes more sense that way anyhow. If I think it'll be useful, I'll post an update.

Have something to contribute to this discussion? Please be thoughtful, detailed and courteous, and be sure to adhere to our posting rules.