Hamza Shezad
Hamza Shezad

Reputation: 35

How can I achieve something like $app->error()->encode() in PHP?

I want to include this function in a class. This function will essentially json_encode the output of the previous function (I hope that makes sense).

I want to do something like this:

<?php

$app = new App;

// $app->error(); // Should return ['some error', 'some other error']

echo $app->error()->encode(); // Should return {'errors': ['some error', 'some other error']}.

Also what's the correct term for such function? I've been searching but couldn't find anything as I didn't really know what I was looking for.

Thanks!

Edit

I think you got that wrong. It's my mistake I didn't mention it before.

That's just an example. Just like in frameworks like Slim, where you can do something like:

$response->getBody()->write('Something');

I want to do something similar to that. Not just that. I want to learn how it's done.

Upvotes: 0

Views: 40

Answers (1)

trincot
trincot

Reputation: 350770

Here is some boilerplate code you could use. The idea is that you should make the error method return an object of yet another class. That object should then in turn have the encode method.

In your example, you want $app->error() to return an array. For it to behave as an array, we can extend the ArrayObject class.

Secondly, you want that same $app->error() to expose another method encode. So you define that method in that same class mentioned above:

// Extend ArrayObject to make objects behave as arrays
class ErrorMsg extends ArrayObject {
    // Add method to return JSON string
    public function encode() {
        return json_encode(array("errors" => $this->getArrayCopy()));
    }
}

class App {
    private $error;
    
    public function doSomething() {
        // For demo sake, just set an error:
        $this->error = ["An error occurred in doSomething", "No further info"];
    }
    
    public function error() {
        // This is the key: instantiate and return another object
        return new ErrorMsg($this->error);
    }
}    

$app = new App;
// Set an error condition in $app
$app->doSomething();
// Loop over error array 
foreach ($app->error() as $index => $error) {
    // Display the error
    echo "Error $index is: $error\n"; 
}
// Display the JSON encoding of the same.
echo $app->error()->encode() . "\n"; 

Output:

Error 0 is: An error occurred in doSomething

Error 1 is: No further info

{"errors":["An error occurred in doSomething","No further info"]}

See it run on eval.in

General idea to chain method calls

In general, when you want your objects to support chained -> notation, you must make sure to define each method as returning yet another object with its own methods. Then those methods can again return objects, with again exposed methods, etc. And so you can chain-call on and on.

So if you want to be able to write:

$a = new A();
$result = $a->b()->c()->d();

...then your code would look something like this:

class D {
    // ...
}

class C {
    private $d;
    public function C() { // constructor
        $this->d = new D();
    }
    public function d() {
        return $this->d; 
    }
}

class B {
    private $c;
    public function B() { // constructor
        $this->c = new C();
    }
    public function c() {
        return $this->c; 
    }
}

class A {
    private $b;
    public function A() { // constructor
        $this->b = new B();
    }
    public function b() {
        return $this->b; 
    }
}

Of course, this is just the structure, and you'd pass some specific data to either the constructors and/or methods. But the main idea is that you never return simple types (String, Number, ...), but always objects.

Upvotes: 1

Related Questions