473,385 Members | 1,661 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,385 software developers and data experts.

chain methods, is it possible to break a chain?

Dear sir,

say, do you know if it is possible to "break" a method chain in php?

e.g.

Expand|Select|Wrap|Line Numbers
  1.  
  2. class a{
  3.  
  4. function x(){
  5.   return $this;
  6. }
  7.  
  8. function y(){
  9.   if(condition===true){
  10.     return $this;
  11.   }
  12.   else{
  13.     return false;
  14.   }
  15. }
  16.  
  17. function z(){
  18.   ...
  19. }
  20.  
  21. $a=new a;
  22.  
  23. $this->x()->y()->z();
  24.  
  25. }
  26.  
  27.  
In the current example if the "condition" in method "y" is false an error will be thrown after y is evaluated, because z() can not be accessed from a non-object (that is "false" which is returned instead of "$this").

What I am trying to do dear sir, is to break the chain at juncture "y", that is,

when y returns false, then z should not be evaluated,

do you my good man know how I can achieve this?

Grateful for answer,

yours sincerely
Sep 9 '09 #1
11 5951
Markus
6,050 Expert 4TB
You could throw an exception instead of returning false, and then run your obj calls in a try/catch block.
Sep 9 '09 #2
Hi again!

Thanks for your reply, and your tips for an approach to this problem,

I'll look into this :D
Sep 9 '09 #3
Markus
6,050 Expert 4TB
@ManWithNoName
No problamo! Let us know how you get on.

Mark.
Sep 10 '09 #4
I never used exceptions, but I can’t see how the basic set up could be used for my problem.

e.g. (in class a)
Expand|Select|Wrap|Line Numbers
  1. public function y(){
  2.   if(condition===true){
  3.     return $this;
  4.   }
  5.   else{
  6.     throw new Exception("false");
  7.   }
  8. }
  9.  
But this still means z() needs to be evaluated… (i.e. the chain won’t “break” at x() and return and thus never invoking z())

I have thought about this, and I don’t think this is possible to do what I want to do… PHP will evaluate the entire chain and expects that the methods are being called from a proper class object where the current called method exists…
Sep 11 '09 #5
Markus
6,050 Expert 4TB
Uh, confused. The code below produces the expected result, that is, the chaining breaks when an exception is thrown:

Expand|Select|Wrap|Line Numbers
  1. <?php
  2.  
  3.     class TestChain { 
  4.  
  5.         public function x() {
  6.             printf("Method %s called\n", __METHOD__);
  7.  
  8.             return $this;
  9.         }
  10.  
  11.         public function y($throw = TRUE) {
  12.             printf("Method %s called\n", __METHOD__);
  13.  
  14.             if($throw) throw new Exception('Breaking');
  15.             else return $this;
  16.         }
  17.  
  18.         public function z() {
  19.             printf("Method %s called\n", __METHOD__);
  20.  
  21.             return $this;
  22.         }
  23.  
  24.     }
  25.  
  26.     $tc = new TestChain;
  27.  
  28.     try {
  29.         // Should eventually evaluate z()
  30.         $tc->x()->y(FALSE)->z();
  31.         print "Method chaing ran well.\n";
  32.     } catch (Exception $e) {
  33.         printf("Method chaining failed: %s\n", $e->getMessage());
  34.     }
  35.  
  36.     try {
  37.         // Should not evaluate z()
  38.         $tc->x()->y(TRUE)->z();
  39.         print "Method chaing ran well.\n";
  40.     } catch (Exception $e) {
  41.         printf("Method chaining failed: %s\n", $e->getMessage());
  42.     }
  43.  
Although, I'm unable to make heads or tails on whether this is what you want or not.

Mark.
Sep 11 '09 #6
Thanks Markus but the problem lies in the “wrapping”, I don’t want to wrap the “chain” with try/catch,

I would like to have all necessary functionality embedded in the methods, in order to have a more “clean” and convenient code ;)

e.g.

Expand|Select|Wrap|Line Numbers
  1. $return=$this->database()->connect()->select_row();
  2. $this->another_method_not_related_to_the_previous_method()->does_something_else(); 
  3.  
The objective is: If connect() fails, return false, then $return will contain “false” and select_row() should never be evaluated,

the problem is that if connect() returns false, then select_row() will throw an error about not being able to init from a non object,

and if connect() returns $this, I have to evaluate a method that does not need to be initiated, and if connect() was false, how would select_row() know this? I would need to pass a variable between them, and that is not pretty :(

EDIT
I just found an example of passing a variable between methods in order to track "false", http://www.hawkhost.com/blog/2009/06...thod-chaining/, I do not like this implementation, but I can't see any other way of doing this...
Sep 11 '09 #7
Markus
6,050 Expert 4TB
@ManWithNoName
Somethings just aren't built into a language, and this isn't into PHP.

@hack: ick! I prefer my elegant try/catch. ;)
Sep 11 '09 #8
Thanks for trying to help me though.
Sep 12 '09 #9
This is an older post, but I'm new to PHP (about a month into it) and found this interresting. After some research I think I've found a more direct solution.

Although, this can be applied with one line of code and absolutely no alterations to the class or methods, there is a catch. This evaluates the method chain twice.

The first time it is evaluated a boolean datatype, as the Logicial Operators work down the chain searching for a not TRUE value.

Basically, here is my 1 line solution:
($class->Ax() && $class ->Ay() && $class->Az()) ? ($result = $class->Ax()->Ay()->Az()) : ($result = FALSE);


Logical Operators
Expand|Select|Wrap|Line Numbers
  1. ($class->Ax() && $class ->Ay() && $class->Az())
Ternary Operator - if
Expand|Select|Wrap|Line Numbers
  1. ?
returned value of Method Chain (if TRUE)
Expand|Select|Wrap|Line Numbers
  1. ($result = $class->Ax()->Ay()->Az()) 
Ternary Operator - then
Expand|Select|Wrap|Line Numbers
  1. :
validate FALSE boolean for a break in the chain.
Expand|Select|Wrap|Line Numbers
  1. ($result = FALSE);
It's not perfect. You can follow the $trace global below to see how it travels the chain twice. However, I think it's effective and a step in the right direction.

Here's a bunch of code, consisting of a basic class and multiple test outputs at the bottom.

Please let me know what you think and how this could be further improved!

Expand|Select|Wrap|Line Numbers
  1. <?PHP
  2. $trace ='';
  3. $result = '';
  4.  
  5. class Main
  6.  
  7.     public $condition_A = TRUE;
  8.     public $condition_B = TRUE;
  9.  
  10.     function Ax(){ 
  11.         $GLOBALS['trace'] .= " --> ". __METHOD__;
  12.         return $this; 
  13.     } 
  14.     function Ay(){ 
  15.         if($this->condition_A===TRUE){ 
  16.         $GLOBALS['trace'] .= " --> ". __METHOD__;
  17.             return $this; 
  18.         } 
  19.         else{return FALSE;} 
  20.     } 
  21.     function Az(){ 
  22.         $GLOBALS['trace'] .= " --> ". __METHOD__;
  23.         return "Your requested row data"; 
  24.     } 
  25.       function Bx(){ 
  26.         $GLOBALS['trace'] .= " --> ". __METHOD__;
  27.         return $this; 
  28.     }
  29.     function By(){ 
  30.         if($this->condition_B===TRUE){ 
  31.             $GLOBALS['trace'] .= " --> ". __METHOD__;
  32.             return $this; 
  33.         } 
  34.         else{
  35.             $GLOBALS['trace'] .= " --> ". __METHOD__;
  36.             return FALSE;
  37.         } 
  38.     } 
  39.     function Bz(){ 
  40.         $GLOBALS['trace'] .= " --> ". __METHOD__;
  41.         return "Your requested row data"; 
  42.     } 
  43.     public function Control(){
  44.         $return = $this->Ax()->Ay()->Az();
  45.         return $return;
  46.     }
  47.  
  48. }
  49.  
  50. $class = new Main;
  51.  
  52. $result = $class->Control();
  53. echo $trace;                    //Output: --> Main::Ax --> Main::Ay --> Main::Az
  54. echo '<br />';
  55. printf (var_dump($result));        //Output: string(23) "Your requested row data" 
  56. echo '<br />';
  57. $trace = $result = NULL;
  58.  
  59. $result = $class->Bx()->By()->Bz();
  60. echo $trace;                    //Output: --> Main::Bx --> Main::By --> Main::Bz
  61. echo '<br />';
  62. printf (var_dump($result));        //Output: string(23) "Your requested row data" 
  63. echo '<br />';
  64. $trace = $result = NULL;
  65.  
  66. $result = $class->Bx() && $class ->By() && $class->Bz();
  67. echo $trace;                    //Output: --> Main::Bx --> Main::By --> Main::Bz
  68. echo '<br />';
  69. printf (var_dump($result));        //Output: string(23) "Your requested row data" 
  70. echo '<br />';
  71. $trace = $result = NULL;
  72.  
  73. $class->condition_B = FALSE;    // <-----  BREAK IN THE CHAIN  --------
  74.  
  75. $result = $class->Bx() && $class ->By() && $class->Bz();
  76. echo $trace;                    //Output: --> Main::Bx --> Main::By
  77. echo '<br />';
  78. printf (var_dump($result));
  79. echo '<br />';                    //Output: bool(false) 
  80. $trace = $result = NULL;
  81.  
  82. $result = $class->Control();
  83. echo $trace;                    //Output: --> Main::Ax --> Main::Ay --> Main::Az
  84. echo '<br />';
  85. printf (var_dump($result));        //Output: string(23) "Your requested row data" 
  86. echo '<br />';
  87. $trace = $result = NULL;
  88. /*
  89. $result = $class->Bx()->By()->Bz();    //Output: Fatal error: Call to a member function Bz() on a non-object in
  90. echo $trace;                     
  91. echo '<br />';
  92. printf (var_dump($result));
  93. echo '<br />';            
  94. */
  95.  
  96. ($class->Ax() && $class ->Ay() && $class->Az()) ? ($result = $class->Ax()->Ay()->Az()) : ($result = FALSE);
  97. echo $trace;                    //Output: --> Main::Ax --> Main::Ay --> Main::Az --> Main::Ax --> Main::Ay --> Main::Az
  98. echo '<br />';
  99. printf (var_dump($result));        //Output: string(23) "Your requested row data" 
  100. echo '<br />';
  101. $trace = $result = NULL;
  102.  
  103. ($class->Bx() && $class ->By() && $class->Bz()) ? ($result = $class->Bx()->By()->Bz()) : ($result = FALSE);
  104. echo $trace;                    //Output: Main::Bx --> Main::By
  105. echo '<br />';
  106. printf (var_dump($result));        //Output: bool(false) 
  107. echo '<br />';
  108. ?>
Jan 29 '10 #10
Dormilich
8,658 Expert Mod 8TB
I’d go along with Markus, Exceptions are easy to handle and extend, plus you can catch Exceptions a) anywhere and b) globally with set_exception_handler() (although that will finish the script).

in this special case, I’d rather build the DB connecting into the select_row() method, so that I don’t even require chaining.

Expand|Select|Wrap|Line Numbers
  1. public function select_row()
  2. {
  3.     try
  4.     {
  5.         $this->database();
  6.         $this->connect();
  7.     }
  8.     catch (Exception $e)
  9.     {
  10.         logException($e);
  11.         return false;
  12.     }
  13.     // select row code
  14.     return true;
  15. }
Jan 29 '10 #11
I first want to apologize to Markus. :)
My inexperience with PHP (and lack of any knowledge of exceptions) drove me to try and find a way to try and out smart the method chain, instead of logically handling the situation as PHP was designed to do.

I've since studied exceptions and now have yet another wonderful tool in my PHP belt.

Thank you for your responce, Dormilich.

I've learned a lot from this thread and am glad I've registered with bytes.
Feb 1 '10 #12

Sign in to post your reply or Sign up for a free account.

Similar topics

99
by: David MacQuigg | last post by:
I'm not getting any feedback on the most important benefit in my proposed "Ideas for Python 3" thread - the unification of methods and functions. Perhaps it was buried among too many other less...
0
by: Anthony Baxter | last post by:
To go along with the 2.4a3 release, here's an updated version of the decorator PEP. It describes the state of decorators as they are in 2.4a3. PEP: 318 Title: Decorators for Functions and...
2
by: dcipher | last post by:
I'm in the process of rewritting my graphics library to be purely OO using C++. The following is a section of my heirarchy of classes: PImage // defines all basic graphics routines as...
1
by: Jeff Smith | last post by:
Can I load custom web user controls dynamically and access the properties and methods without having to explicitly define custom control types (example 2 below). I have custom web control named...
10
by: r035198x | last post by:
The Object class has five non final methods namely equals, hashCode, toString, clone, and finalize. These were designed to be overridden according to specific general contracts. Other classes that...
318
by: King Raz | last post by:
The shootout site has benchmarks comparing different languages. It includes C# Mono vs Java but not C# .NET vs Java. So I went through all the benchmark on the site ... ...
2
by: DanYan | last post by:
So I was doing some stuff in Javascript, and I want to get access to a function's scope chain. As a simplified example of what I actually am trying to do, suppose I have this: function add(b)...
15
by: jzakiya | last post by:
I'm translating a program in Python that has this IF Then chain IF x1 < limit: --- do a --- IF x2 < limit: --- do b --- IF x3 < limit: --- do c --- .----- ------ IF x10 < limt: ---...
6
by: vwkng1987 | last post by:
Hi everyone Please look at the code below: (I am picking up JS from Crockfold and a few other online sources too) *************************************************************** function...
1
by: CloudSolutions | last post by:
Introduction: For many beginners and individual users, requiring a credit card and email registration may pose a barrier when starting to use cloud servers. However, some cloud server providers now...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 3 Apr 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome former...
0
by: ryjfgjl | last post by:
In our work, we often need to import Excel data into databases (such as MySQL, SQL Server, Oracle) for data analysis and processing. Usually, we use database tools like Navicat or the Excel import...
0
by: taylorcarr | last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.