1

I often like to have classes take care of a whole task. Call the class with some arguments and then get the result.

I can't do this:

<?php
class MyClass{
    function __construct() {
        $this->one = $this->one();
        $this->two = $this->two();
        $this->three = $this->three();

        return $this->three;
    }

    function one() {
        $output = 'One';
        return $output;
    }

    function two() {
        $output = $this->one . 'Two';
        return $output;
    }

    function three() {
        $output = $this->two . 'Three';
        return 'Three' . $this->two;
    }
}

echo new MyClass();

I can do this:

<?php
class MyClass{
    function run() {
        $this->one = $this->one();
        $this->two = $this->two();
        $this->three = $this->three();

        return $this->three;
    }

    function one() {
        $output = 'One';
        return $output;
    }

    function two() {
        $output = $this->one . 'Two';
        return $output;
    }

    function three() {
        $output = $this->two . 'Three';
        return 'Three' . $this->two;
    }
}

$obj = new MyClass();
echo $obj->run();

But is the above really the correct way to do it? Then I don't see the need for a construct.

1
  • If you don't need something - don't use it. Commented Sep 22, 2016 at 7:02

4 Answers 4

4

The proper way to use a class' constructor, is to have it set up the class ready to be used. In many instances the constructor doesn't do much beside accept the dependencies (database object, for instance), and saves these for later use.
(Ab)using the constructor as you've done in your first example leads to many difficulties along the line, mostly due to the fact that simply creating an object has additional side-effects beside just creating said object.

In that manner your second example is a lot closer to what object-oriented programming really is, even though you're still not really taking advantage of anything that using a class gives you. In fact, it would have been better off written as purely procedural code.

While I do not know what your code does, I've attempted to make an example taking advantage of features using a class gives you:

    /**
     * We need a DB connection in case we need to get something from the database.
     * This is called a dependency, and we save it in the object at object creation time.
     * 
     * Nothing that causes the object itself to do "work" is supposed to be here, only things
     * necessary for actually creating the object in a state where we can _start_ working with it.
     * 
     * @param PDO $db
     */
    public function __construct (PDO $db) {
        $this->db = $db;
    }

    /**
     * Sets the value for each step. Legal values for $step is between 1 and 3, inclusive.
     * Normally we'd have many setters, one for each property we want to change from outside.
     * That can be anything from address to price and anything else one can think of.
     * 
     * @param int $step
     * @param int|string $value
     * 
     * @throws InvalidArgumentException
     * @return void
     */
    public function set_value ($step, $value) {
        if ($step <= 0 || $step > 3) {
            throw new InvalidArgumentException("Step must be between 1 and 3, inclusive.");
        }

        $this->value[$step] = $value;
    }

    /**
     * This is where the actual processing is done.
     * In a normal class there would be several such functions
     * each doing one specific thing (creating a new record, saving
     * it to the database, validating stuff, etc).
     * 
     * @return void
     */
    public function do_processing () {
        $this->result = implode(", ", $this->data);
    }

    /**
     * Fetches the result of the class. Normally we have many getters, which return
     * one part of the data associated with the object. Such as username, hash, email, etc.
     * 
     * These are often in a 1-1 relationship with setters.
     * 
     * @return string
     */
    public function get_result () {
        // If we have no calculated result, fetch it from the DB instead.
        if (empty($this->result)) {
            return $this->db->get_cached_result ();
        }
        // Returns the newly calculated result.
        // Should probably also cache it, to make the above line useful.
        return $this->result;
    }
}

// A DB interface class, which extends PDO. 
$db = new MyClassDB ();

$obj = new MyClass ($db);
$obj->set_value (2, "Two");
$obj->set_value (1, "One");
$obj->set_value (3, "Three");
$obj->do_processing();
echo $obj->get_result();

Please note that this is a pretty trivial class, and doesn't give you a very good picture of how to leverage classes properly. I recommend looking at a more fleshed out class, which you can find in any of the major frameworks.

Sign up to request clarification or add additional context in comments.

4 Comments

Don't you need to add a an argument here: $obj = new MyClass(); to insert the database to the construct?
@JensTörnell: You are indeed correct. Thank you for catching this. :) I've updated my answer to include this.
I think I finally understand how to work with OOP. I guess I needed a really short example based on my own code to see it. Great thanks! Not to be a nag but I also think $obj->set_value1 ( should be $obj->set_value (? My guess is that you modified your class methods and forgot to modify the method calls?
Hehe, no nagging. Just glad people help me spot the errors, so that they can be corrected. :) Not sure how that 1 ended up there, but... Anyway, glad I could help.
0

You could define your class methods as static, then call them "statically" as PHP likes to say. Like so,

<?php
class MyClass {

private static $one;
private static $two;
private static $three;

public static function run() {
     self::$one = self::one();
     self::$two = self::two();
     self::$three = self::three();

     echo self::$three;
}

private static function one() {
    return 'One';
}

private static function two() {
    return self::$one . 'Two';
}

private static function three() {
    return self::$two . 'Three';
}
}

MyClass::run();

?>

1 Comment

You can also change it to return self::$three and call echo MyClass::run() instead, like it was in your original example.
-1

not recommended to use the constructor's return value.

class MyClass{
    function __construct() {
        $this->one = $this->one();
        $this->two = $this->two();
        $this->three = $this->three();

        echo $this->three;
    }

    function one() {
        $output = 'One';
        return $output;
    }

    function two() {
        $output = $this->one . 'Two';
        return $output;
    }

    function three() {
        $output = $this->two . 'Three';
        return 'Three' . $this->two;
    }
}

new MyClass();

5 Comments

Why should you not use constructor return?
Roughly speaking, in OOP, constructors are there to initialize an object internally. They shouldn't properly "do anything" to an outside observer, like return values other than Errors/Exceptions, or use echo statements. Their work is strictly an inside job for the new object (like opening database connections or checking for file existence, etc)
I was hoping that zhenglc can edit their answer and add this information.
I knew I shoulda stayed quiet lol. Ok leaving this part alone.
@SomeDude it's useful comments but I was more angling for getting the answerer to improve their answer, code only answers are not very helpful. And statement that something is not recommended is always improved with a little detail as to why :-) (saying that, my answer on this question is a bit pants too :-/ )
-1
<?php
class MyClass{
    private $one; //private or public or protected. 
    private $two; //placeholder class variables. 
    private $three;

    function __construct() {   
        $this->run();
    }

    function run(){
        $this->one(); //set value one
        $this->two(); //set value two
        print $this->three(); //set and then output value 3.
    }

    function one() {
        $output = 'One';
        return $output;
    }

    function two() {
        $output = $this->one . 'Two';
        return $output;
    }

    function three() {
        $output = $this->two . 'Three';
        return 'Three' . $this->two;
    }
}

//printed output from run automatically given to output buffer.    
// can't print 'new class' syntax. 
new MyClass(); //outputs result of function three();

What the reworked class does is that the variables have been moved to being class variables rather than all set within the __construct, then these are each set with the associated methods before the final one being returned as per the original.

3 Comments

1. Constructors should not be used to do work. 2. __construct () returns the created object, using return here is BAD CODE. Not sure it would work even, to be honest. In most languages this will either cause a fatal error, or simply be ignored. 3. This is still procedural code, making the use of a class completely wasted.
@ChristianF thanks for the clarification; can the constructor not just call the run method and not return, with the run method returning its own values? (so it works with removing the return word from the constructor, the result of therun function would still be passed back to the main script when the new object is created?)
It is perfectly possible to have an empty constructor (or rather not define it in the first place). It's not uncommon to see this in production code, especially if the class doesn't have any dependencies. However, by just chaining methods after one another in a wrapper method, and not doing anything else with the class, you're still just adding lots of code for no benefit. The code itself will still be procedural, and as such should be written without using classes. See my answer for a simple OOP-approach.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.