SitePoint Sponsor

User Tag List

Results 1 to 17 of 17
  1. #1
    SitePoint Addict bronze trophy
    Join Date
    Apr 2013
    Location
    Ithaca
    Posts
    351
    Mentioned
    6 Post(s)
    Tagged
    1 Thread(s)

    Pass func_get_args() to another method or an object?

    Well I was wondering, is there a way to pass func_get_args() to another method in the same class or to use it in the constructor of an object without explicitly calling func_get_args()? The idea is that I want to have a root class protected method to handle variable arguments passing using a class/object called Argument, which has some interesting methods to manipulate arguments/parameters. In this way, I do not have to call func_get_args() in every method that accepts variable number of arguments, while a special helper method will do the trick. Also func_get_args() always returns a PHP native array, I want such a function/method to return a collection object.

    The problem is, func_get_args() is only available in the scope of the initial function call, if you call func_get_args() from second method in the first method, the argument list passed to the first method will not be available in the second method unless you explicitly pass func_get_args() in the method call. I was wondering if this following syntax is valid:

    PHP Code:
    class A{
        public function 
    a(){
            
    $argObject $this->b();
            ... 
    additional work ...
        }

        private function 
    b($args func_get_args()){
            ... 
    convert $args into object ...
            return 
    $argObject;
        }
    }

    $obj = new A;
    $obj->a($arg$arg2$arg3...); 
    In theory, the func_get_args() default value in method b() is the argument list from client method call $obj->a($arg, $arg2, $arg3...). The idea is that func_get_args() will not be explicitly called in $this->b() method call, but I doubt PHP allows that. If not, is there another way to get around if I just dont want to explicitly write func_get_args() in every method that accept variable arguments?

  2. #2
    SitePoint Guru bronze trophy TomB's Avatar
    Join Date
    Oct 2005
    Location
    Milton Keynes, UK
    Posts
    989
    Mentioned
    9 Post(s)
    Tagged
    2 Thread(s)
    Quote Originally Posted by Hall of Famer View Post
    Well I was wondering, is there a way to pass func_get_args() to another method in the same class or to use it in the constructor of an object without explicitly calling func_get_args()? The idea is that I want to have a root class protected method to handle variable arguments passing using a class/object called Argument, which has some interesting methods to manipulate arguments/parameters. In this way, I do not have to call func_get_args() in every method that accepts variable number of arguments, while a special helper method will do the trick. Also func_get_args() always returns a PHP native array, I want such a function/method to return a collection object.

    The problem is, func_get_args() is only available in the scope of the initial function call, if you call func_get_args() from second method in the first method, the argument list passed to the first method will not be available in the second method unless you explicitly pass func_get_args() in the method call. I was wondering if this following syntax is valid:

    PHP Code:
    class A{
        public function 
    a(){
            
    $argObject $this->b();
            ... 
    additional work ...
        }

        private function 
    b($args func_get_args()){
            ... 
    convert $args into object ...
            return 
    $argObject;
        }
    }

    $obj = new A;
    $obj->a($arg$arg2$arg3...); 
    In theory, the func_get_args() default value in method b() is the argument list from client method call $obj->a($arg, $arg2, $arg3...). The idea is that func_get_args() will not be explicitly called in $this->b() method call, but I doubt PHP allows that. If not, is there another way to get around if I just dont want to explicitly write func_get_args() in every method that accept variable arguments?

    I question the separation of concerns here, but:

    PHP Code:
    class A{
        public function 
    a(){
            
    $args func_get_args();
            
    $argObject call_user_func_array(array($this,'b'), $args);

        }

        private function 
    b(){
            
    $args func_get_args();
            return 
    $argObject;
        }
    }

    $obj = new A;
    $obj->a($arg$arg2$arg3...); 

  3. #3
    I solve practical problems. bronze trophy
    Michael Morris's Avatar
    Join Date
    Jan 2008
    Location
    Knoxville TN
    Posts
    2,026
    Mentioned
    64 Post(s)
    Tagged
    0 Thread(s)
    func_get_args isn't a function. It's a language construct. It returns the arguments passed to the current function as an array.

    Also, you cannot set the default value of an argument to anything other than a constant value.

  4. #4
    SitePoint Addict bronze trophy
    Join Date
    Apr 2013
    Location
    Ithaca
    Posts
    351
    Mentioned
    6 Post(s)
    Tagged
    1 Thread(s)
    I see, what a pity. Guess I will be working on an Argument class then, the idea is to encapsulate func_get_args() though so that you don't need to call them explicitly in the methods that accept variable number of arguments.

  5. #5
    SitePoint Evangelist
    Join Date
    Oct 2005
    Location
    Michigan, USA
    Posts
    434
    Mentioned
    2 Post(s)
    Tagged
    0 Thread(s)
    It isn't going to happen and you aren't going to save much anyway if you could. I'll convert your original sketch to something that would do what you want. You'll see it's almost the same. Yes, you have to put func_get_args() in there for each instance you want to use it, but that's not so bad, is it?

    Before
    PHP Code:
    class A
        public function 
    a(){ 
            
    $argObject $this->b(); 
            ... 
    additional work ... 
        } 

        private function 
    b($args func_get_args()){ 
            ... 
    convert $args into object ... 
            return 
    $argObject
        } 

    After
    PHP Code:
    class A
        public function 
    a(){ 
            
    $argObject $this->bfunc_get_args() ); 
            ... 
    additional work ... 
        } 

        private function 
    b( array $args ){ 
            ... 
    convert $args into object ... 
            return 
    $argObject
        } 

    The only way I see getting close is to use __call() for each of the methods in question. I wouldn't want to go down this path myself though.
    PHP Code:
    class A{  
        private function 
    _a$argObject ){  
            ... 
    additional work ...  
        }  

        private function 
    b( array $args ){  
            ... 
    convert $args into object ...  
            return 
    $argObject;  
        }  
      
      public function 
    __call$name$args ) {
        
    // do some sanity checks here

        
    $method "_{$name}";
        return 
    $this->{$method}( $this->b$args ) );
      }

    - Robert

  6. #6
    SitePoint Guru bronze trophy TomB's Avatar
    Join Date
    Oct 2005
    Location
    Milton Keynes, UK
    Posts
    989
    Mentioned
    9 Post(s)
    Tagged
    2 Thread(s)
    Quote Originally Posted by QMonkey View Post
    It isn't going to happen and you aren't going to save much anyway if you could. I'll convert your original sketch to something that would do what you want. You'll see it's almost the same. Yes, you have to put func_get_args() in there for each instance you want to use it, but that's not so bad, is it?

    Before
    PHP Code:
    class A
        public function 
    a(){ 
            
    $argObject $this->b(); 
            ... 
    additional work ... 
        } 

        private function 
    b($args func_get_args()){ 
            ... 
    convert $args into object ... 
            return 
    $argObject
        } 

    After
    PHP Code:
    class A
        public function 
    a(){ 
            
    $argObject $this->bfunc_get_args() ); 
            ... 
    additional work ... 
        } 

        private function 
    b( array $args ){ 
            ... 
    convert $args into object ... 
            return 
    $argObject
        } 

    The only way I see getting close is to use __call() for each of the methods in question. I wouldn't want to go down this path myself though.
    PHP Code:
    class A{  
        private function 
    _a$argObject ){  
            ... 
    additional work ...  
        }  

        private function 
    b( array $args ){  
            ... 
    convert $args into object ...  
            return 
    $argObject;  
        }  
      
      public function 
    __call$name$args ) {
        
    // do some sanity checks here

        
    $method "_{$name}";
        return 
    $this->{$method}( $this->b$args ) );
      }



    What I'm not sure I understand here is what's wrong with either:

    PHP Code:
    class {
        public function 
    a() {
            
    $args func_get_args();
            
    $this->b($args);
        }
        
        private function 
    b($args) {
            
        }

    Or:

    PHP Code:

    class {
        private 
    $args;
        
        public function 
    a() {
            
    $this->args func_get_args();
        }
        
        private function 
    b($args) {
            
    //do something with
            
    $this->args; /
        }




    However, internal method chaining like that (using a direct $this->method() without going via a dependency) often hints at a poor separation of concerns. Is a() really just passing the arguments on to b()? For what purpose?

    Really you have two different responsibilities here. Converting a set of args into an $argObject and utilising the $argObject which has been created. This is almost certainly a better solution:


    PHP Code:
    class {
        private 
    $args;

        public function 
    a(ArgObject $args) {
            
    //Do whatever with $argObject
        
    }
    }


    $argObject = new ArgObject($arg1$arg2$arg3, ....);
    $a = new A();
    $a->a($argObject); 
    Your code, as it stands, likely suffers from Flaw: Class Does Too Much because it has two entirely different responsibilities, formatting the arguments and processing them, by moving it into two different objects, the responsibility has moved. This frees up the extra responsibility that A had and it means that A never needs to worry about how/where its argObject was created. In terms of flexibility this opens you up to polymorphism and runtime configuration which would previously have been impossible.

  7. #7
    SitePoint Addict bronze trophy
    Join Date
    Apr 2013
    Location
    Ithaca
    Posts
    351
    Mentioned
    6 Post(s)
    Tagged
    1 Thread(s)
    Oh I am sorry I did not explain the situation clear and instead used a poor example. I believe it has nothing to do with violating single responsibility rule, the fact is that in my application every class extends from a root class called Object, while the object class provides functionality needed by all classes(such as object comparison, hash code computation, serialization etc). Since it's possible for all classes to have methods that accept variable number of arguments, I am considering designing a method in the root object class that handles this situation so that each child class do not have to call func_get_args() and play with the array it returns. This method is called Object::getArgs(), which returns an Argument object that contains detailed information for all parameters passed into the method. If func_get_args() can be sent from one method to another without explicit declaration, the following code will work nicely:

    PHP Code:
    abstract class Object{
        public function 
    getArgs($args func_get_args()){
            
    $argument = new Argument($args);
            
    //Code to manipulate each variable argument
            
    return $argument 
        
    }
    }

    class 
    extends Object{
        public function 
    a(){
            
    $argument $this->getArgs();
            
    // code for method a(), which uses argument object.
        

    }

    class 
    extends Object{
        public function 
    b(){
            
    $argument $this->getArgs();
            
    // code for method b(), which also uses argument object returned from parent method getArgs().
        
    }
    }

    objA = new A;
    $objA->a($arg$arg2);
    objB = new B;
    $objB->b($arg$arg2$arg3); 
    In this way, func_get_args() is only directly accessed and used by the root object class, Id say its a really nice approach to encapsulate this function and subsequent operations based on it. Unfortunately, the code above wont work since PHP's func_get_args() has a serious scope issue, for this reason child classes will always have to pass func_get_args() explicitly into the parent method Object::getArgs(), it then becomes Object::getArgs(func_get_args()). It takes more typing for sure, but a bigger concern is elegance, at least for me. Thats why I've been seeking ways to perfectly encapsulate func_get_args(), looks like the most ideal approach won't work out for me. I will have to think of another way then, such as having clients creating argument object explicitly like this:

    PHP Code:
    $objA = new A;
    $objA->a(new Argument($arg$arg2));
    objB = new B;
    $objB->b(new Argument($arg$arg2$arg3)); 
    And the argument object's constructor will handle func_get_args() and its subsequent operations instead. Id say its better than having each variable argument methods calling func_get_args() at least, but still not as good as the first approach I proposed. *sigh*

  8. #8
    SitePoint Guru bronze trophy TomB's Avatar
    Join Date
    Oct 2005
    Location
    Milton Keynes, UK
    Posts
    989
    Mentioned
    9 Post(s)
    Tagged
    2 Thread(s)
    I would definitely suggest that making everything inherit from a base class clearly violates SRP because you are, by definition, adding extra responsibilities to each class which extends it. Inheritance, in most cases, is a bad idea. Let's take serialisation as an example since you mentioned it:

    This:

    PHP Code:
    $object->serialize(); 
    Is less useful than:

    PHP Code:
    $serializer->serialize($object); 
    Why? Because the serialize behaviour is a different behaviour than the responsibility of whatever the object is. The serializer could do a standard php serialize or serialize to JSON, serialize to a url encoded form string or anything. To achieve this using $object->serialize() you either need a switch statement in the serialize method, which will only *ever* be able to serialize into formats that the serialize method supports, or you need to add a specific serialization method for each type. $object->serializeToJson(); for example.

    Using a serializer class, the serialize needs only one method:

    PHP Code:
    interface Serialize {
        public function 
    serialize($object);
    }

    class 
    Serializer implements Serialize {
        public function 
    serialize($object) {
            return 
    serialize($object);
        }
    }

    class 
    JsonSerializer implements Serialize {
        public function 
    serialize($object) {
            return 
    json_encode($object);
        }


    This is a perfect example of polymorphism in action, you can pass a fully constructed $serialize object around, and it will serialize it into a format decided at the point when $serialize was created. Using $obj->serialize() the serialisation method is hard coded because it's based on the return value of the object's serialization method.


    Your problem is definitely that you have a poor separation of concerns. Extending all objects from a base class is a bad idea because it severely reduces portability of individual components.

  9. #9
    SitePoint Wizard bronze trophy Jeff Mott's Avatar
    Join Date
    Jul 2009
    Posts
    1,259
    Mentioned
    18 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by TomB View Post
    I would definitely suggest that making everything inherit from a base class clearly violates SRP because you are, by definition, adding extra responsibilities to each class which extends it. Inheritance, in most cases, is a bad idea. Let's take serialisation as an example since you mentioned it:

    This:

    PHP Code:
    $object->serialize(); 
    Is less useful than:

    PHP Code:
    $serializer->serialize($object); 
    Why? Because the serialize behaviour is a different behaviour than the responsibility of whatever the object is. The serializer could do a standard php serialize or serialize to JSON, serialize to a url encoded form string or anything. To achieve this using $object->serialize() you either need a switch statement in the serialize method, which will only *ever* be able to serialize into formats that the serialize method supports, or you need to add a specific serialization method for each type. $object->serializeToJson(); for example.

    Using a serializer class, the serialize needs only one method:

    PHP Code:
    interface Serialize {
        public function 
    serialize($object);
    }

    class 
    Serializer implements Serialize {
        public function 
    serialize($object) {
            return 
    serialize($object);
        }
    }

    class 
    JsonSerializer implements Serialize {
        public function 
    serialize($object) {
            return 
    json_encode($object);
        }


    This is a perfect example of polymorphism in action, you can pass a fully constructed $serialize object around, and it will serialize it into a format decided at the point when $serialize was created. Using $obj->serialize() the serialisation method is hard coded because it's based on the return value of the object's serialization method.


    Your problem is definitely that you have a poor separation of concerns. Extending all objects from a base class is a bad idea because it severely reduces portability of individual components.
    Like, +1, Upvote, etc.
    "First make it work. Then make it better."

  10. #10
    SitePoint Addict bronze trophy
    Join Date
    Apr 2013
    Location
    Ithaca
    Posts
    351
    Mentioned
    6 Post(s)
    Tagged
    1 Thread(s)
    Quote Originally Posted by TomB View Post
    I would definitely suggest that making everything inherit from a base class clearly violates SRP because you are, by definition, adding extra responsibilities to each class which extends it. Inheritance, in most cases, is a bad idea. Let's take serialisation as an example since you mentioned it:

    This:

    PHP Code:
    $object->serialize(); 
    Is less useful than:

    PHP Code:
    $serializer->serialize($object); 
    Why? Because the serialize behaviour is a different behaviour than the responsibility of whatever the object is. The serializer could do a standard php serialize or serialize to JSON, serialize to a url encoded form string or anything. To achieve this using $object->serialize() you either need a switch statement in the serialize method, which will only *ever* be able to serialize into formats that the serialize method supports, or you need to add a specific serialization method for each type. $object->serializeToJson(); for example.

    Using a serializer class, the serialize needs only one method:

    PHP Code:
    interface Serialize {
        public function 
    serialize($object);
    }

    class 
    Serializer implements Serialize {
        public function 
    serialize($object) {
            return 
    serialize($object);
        }
    }

    class 
    JsonSerializer implements Serialize {
        public function 
    serialize($object) {
            return 
    json_encode($object);
        }


    This is a perfect example of polymorphism in action, you can pass a fully constructed $serialize object around, and it will serialize it into a format decided at the point when $serialize was created. Using $obj->serialize() the serialisation method is hard coded because it's based on the return value of the object's serialization method.


    Your problem is definitely that you have a poor separation of concerns. Extending all objects from a base class is a bad idea because it severely reduces portability of individual components.
    Well you have a good point, I definitely try not to give the root class too much responsibility, definitely not what almost all subclasses actually use. The Object::hashCode() method for instance, is used by every subclass for equality comparison, so yeah its there for a reason. In my system the standard object serialization is far more common than Json-Serialization, which is why each object has a built-in serialize() method. Sure in minor cases when Json-serialization is needed, I will past the very object to a special Json-Serializer object, such cases are rare though. Maybe constructing argument object is not an appropriate responsibility for the root object, if so I will make some changes.

    Anyway, there is a reason why almost all OO languages like Smalltalk, Java, C#, Objective-C, Python and Ruby there is a root object class that is parent to all classes. I dont think theres anything wrong with that, after all all objects/classes share certain behaviors, the bottom-line is to make sure the root class does not do more than what its supposed to, dont you agree?

  11. #11
    SitePoint Guru bronze trophy TomB's Avatar
    Join Date
    Oct 2005
    Location
    Milton Keynes, UK
    Posts
    989
    Mentioned
    9 Post(s)
    Tagged
    2 Thread(s)
    Quote Originally Posted by Hall of Famer View Post
    Well you have a good point, I definitely try not to give the root class too much responsibility, definitely not what almost all subclasses actually use. The Object::hashCode() method for instance, is used by every subclass for equality comparison, so yeah its there for a reason. In my system the standard object serialization is far more common than Json-Serialization, which is why each object has a built-in serialize() method. Sure in minor cases when Json-serialization is needed, I will past the very object to a special Json-Serializer object, such cases are rare though. Maybe constructing argument object is not an appropriate responsibility for the root object, if so I will make some changes.

    Anyway, there is a reason why almost all OO languages like Smalltalk, Java, C#, Objective-C, Python and Ruby there is a root object class that is parent to all classes. I dont think theres anything wrong with that, after all all objects/classes share certain behaviors, the bottom-line is to make sure the root class does not do more than what its supposed to, dont you agree?

    The same thing with hashCode() is it used by every object in the system, really? Does every object that even exists have its hashCode() used in some way or is hashCode() there in case you might, maybe, occasionally need it? Keep in mind that PHP already supports object comparison without you needing to write your own method to do it.

    The problem is, the root class, by providing behaviour, is already doing more than it needs to. Classes, not just the root class, should expose as few behaviours as they possibly need to fulfil their sole responsibility. An object shouldn't understand the concept of serialization, it shouldn't understand that it needs to be hashed, these things are external behaviours that will act on the object, not behaviours which help the object fulfil its responsibility.

    Think of it this way: The object will only provide those methods because the developer has made some decisions about what the object needs to do based on the environment in which the object will be sitting. This breaks encapsulation because the object is essentially aware of the system it's going to be used in and provides specific methods to allow for that. If you can remove a method from a class and the object still fulfils its (single!) responsibility then the method does not belong in the class.

  12. #12
    SitePoint Addict bronze trophy
    Join Date
    Apr 2013
    Location
    Ithaca
    Posts
    351
    Mentioned
    6 Post(s)
    Tagged
    1 Thread(s)
    Well so you are saying that its actually a poor OO design for all these OO languages to extend from root object class? Never thought of this, maybe I will remove some methods from the root object class and make it as light-weight as possible, even as a marker. I'd say its still useful in type hinting though, in my collections framework for instance, these collections only accept object that belong to classes extending from the root object class.

  13. #13
    SitePoint Guru bronze trophy TomB's Avatar
    Join Date
    Oct 2005
    Location
    Milton Keynes, UK
    Posts
    989
    Mentioned
    9 Post(s)
    Tagged
    2 Thread(s)
    In strictly typed languages it makes sense for everything to inherit a base type for the purposes of hinting, and it would be useful to be able to type hint objects in PHP. Whether being able to type hint objects is worth the downsides when it comes to portability and flexibility is debatable and I'd err on the side of maximum flexibility. Since PHP has an object comparison operator, putting this in a base class is entirely redundant and will only add potential for inconsistency and confusion.

    The issue here is type hinting. If you're type hinting a specific type then you're saying "This method must take an object of this type because it needs to call a specific method provided by this type". This ensures a contract between the object and the method. The method needs to call $object->something() so type hint the most primitive thing that has the something() method, be it an interface or a specific class. Only type hint what you need. Don't ask for a class which is 3 levels down an inheritance tree when the class at the top level provides the required methods, hint that instead as it will give you greater flexibility.

    As for marker interfaces, they're a bad idea. I've posted about this on my blog, but don't just take my word for it: http://msdn.microsoft.com/en-US/libr...(v=vs.80).aspx

  14. #14
    I solve practical problems. bronze trophy
    Michael Morris's Avatar
    Join Date
    Jan 2008
    Location
    Knoxville TN
    Posts
    2,026
    Mentioned
    64 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by TomB View Post
    As for marker interfaces, they're a bad idea.
    Usually, but even the article you cite gives a situation where they are acceptable.

  15. #15
    SitePoint Guru
    Join Date
    Nov 2003
    Location
    Huntsville AL
    Posts
    689
    Mentioned
    4 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Hall of Famer View Post
    Well so you are saying that its actually a poor OO design for all these OO languages to extend from root object class? Never thought of this, maybe I will remove some methods from the root object class and make it as light-weight as possible, even as a marker. I'd say its still useful in type hinting though, in my collections framework for instance, these collections only accept object that belong to classes extending from the root object class.
    It is perhaps instructive to see what those base objects in other languages actually do.
    In Java we have : http://docs.oracle.com/javase/7/docs...ng/Object.html

    Just about everything in there is already provided by php including: http://php.net/manual/en/function.spl-object-hash.php

    So from an abstract point of view, you can say that php does indeed have a base class. Just no need to explicitly extend from it.

    As far as collections go, define a collections interface and use it where applicable. No need for a fixed inheritance structure.

  16. #16
    I solve practical problems. bronze trophy
    Michael Morris's Avatar
    Join Date
    Jan 2008
    Location
    Knoxville TN
    Posts
    2,026
    Mentioned
    64 Post(s)
    Tagged
    0 Thread(s)
    K(n) is your worst enemy as a programmer, and most design patterns are designed to fight it.

    @Hall of Famer - What you are encountering is the conflicting goals of code reuse and code scope creep. While we definitely don't want to duplicate code, we also don't want a block of code that is a universal can opener because the more areas of code it must interact with, the harder it is to test. This is especially true of classes because, usually, they have some amount of internal state.

    Functions don't - well, they shouldn't, even if it is possible to give a function internal state using static variables, but it's VERY BAD DESIGN(TM) to have a function with an internal state. Consider this tiny function

    Code php:
    function array_sum( $a) {
      $r = 0;
      foreach ($a as $v) {
        $r += v;
      }
      return $r;
    }
    // Sue me for using one letter variable names, I'm tired.

    As a function array_sum could be called from anywhere. However, since it has no internal state it should be testable all the same. Also, it doesn't act on any data in the global scope, another common pitfall of PHP programming (If I ever teach a PHP class I will fail any assignment that uses the global statement, even if it works).

    I'm digressing. The less code needs to know about the rest of the application, the better, even if any part of the application could call it. Scoping (private, protected, public) sets up barriers to contact between disparate blocks of code to make the application easier to work with in the long term, even if in the short term there are headaches.
    .

  17. #17
    SitePoint Addict bronze trophy
    Join Date
    Apr 2013
    Location
    Ithaca
    Posts
    351
    Mentioned
    6 Post(s)
    Tagged
    1 Thread(s)
    I see, I will keep this in mind, thank you for your advice.


Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •