17

How can I do this in PHP

$myDBClass->users()->limit(5);//output you limited users to 5 $myDBClass->comments()->limit(3);//output you limited comments to 3 

what I meant is nested methods or nested class (I don't know!) so when I call the limit method as a child of users it will know that I am calling it from "users" method -or class- and when I call limit method -or class!- from comments It also knows that.

what is the possible structure for a PHP class to do this thing?


the reason for this question because I am working on my own class for database so I can easily use something like this

 $DB->comments()->id(" > 3")->limit(10); 

to generate the sql code "select * from comments where id > 3 limit 10" Thanks

2
  • 8
    Dude this is chaining, not nesting. Commented Mar 13, 2015 at 13:41
  • @Pacerier Exactly. A nesting would look like this post: stackoverflow.com/questions/16424257/… And as mentioned there it is not possible with PHP yet. Commented Aug 22, 2023 at 9:34

3 Answers 3

22

Have the methods return objects with the methods described, and you get what you are after.

So, as long as $DB is an object that has a comments()-method, that part is valid. If that comments() returns an object that has an id()-method, that part is valid, too. Then, id() needs to return an object that has the limit()-method.

In your particular case, you might want to do something like this:

class DB { public function comments() { // do preparations that make the object select the "comments"-table... return $this; } public function id($string) { // handle this too... return $this; } public function limit($int) { // also this return $this; } public function execute() { $success = try_to_execute_accumulated_db_commands(); return $success; } } $DB = new DB(); $DB->comments()->id(" > 3")->limit(10); 

In my example, every method (also not depicted here) would return the object itself, so that commands can be chained together. When the construction of the database query is done, you actually evaluate the query by invoking execute() that (in my case) would return a boolean that would represent the success of the database execution.

User nickohm suggested that this is called a fluent interface. I must admit that this is a new term for me, but that tells probably more of my knowledge, than the term's usage. ("I just write code, you know...")

Note: $this is a 'magic' variable that points to the currently active object. As the name suggests, it just returns itself as the return value for the method.

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

3 Comments

Great example. I was just about to posts something exactly the same. Might want to mention this is called a fluent interface: en.wikipedia.org/wiki/Fluent_interface
This is used in ExtPHP nexus.zteo.com/2008/03/04/…
The method chaining is know as Chain of Responsibility or short COR. see refactoring.guru/design-patterns/chain-of-responsibility
11

The standard convention for this is to return the instance of $this at the end of each of the method call. So when returned to the caller we are then just referencing another method call.

class Foo { public function do_something() { return $this; } public function do_something_else() { return $this; } } $foo = new Foo(); $foo->do_something()->do_something_else(); 

Comments

0

A simple to implement method to get you started might go like:

class db { public function __call($function, $arguments) { switch($function) { // implement table handling here case 'user': //do something return $something; break; } } } 

Depending on whether or not you want to go complicated, but solid or simple, but less flexible you might implement two different strategies. Simple strategy might go like so:

class db { protected $operatingTable; public function limit($limitNumber) { return $this->executeQuery("SELECT * FROM ".$this->operatingTable." LIMIT ".$limitNumber); // where executeQuery is a function that runs a query } public function __call($function, $arguments) { switch($function) { // implement table handling here case 'user': $this->operatingTable='user'; // alternately, but less secure: $this->operatingTable=$function; return $this; break; } } } 

Alternately, but more powerful:

class db { protected $operatingTable; public function limit($limitNumber) { return $this->executeQuery("SELECT * FROM ".$this->operatingTable." LIMIT ".$limitNumber); // where executeQuery is a function that runs a query } public function __call($function, $arguments) { switch($function) { // implement table handling here case 'user': $user = new user($this); // pass in the database to the object, so the table object can have a reference to the db return $user; break; } } } class baseTableClass { protected $db; // an instance of class db function limit($limitNumber) { $db->execute($aStatementDerivedFromThisClassesInformation); // execute a sql command, based on information about the table in the class } } class user extends baseTableClass { public function __construct($db) { $this->db = $db; } } 

You get the idea. Either overload the db object, or create a base db object, and table objects, putting much of the intelligence in table objects, ensuring that when created, a table object stores a reference to the db object

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.