SitePoint Sponsor

User Tag List

Page 2 of 2 FirstFirst 12
Results 26 to 40 of 40
  1. #26
    . shoooo... silver trophy logic_earth's Avatar
    Join Date
    Oct 2005
    Location
    CA
    Posts
    9,013
    Mentioned
    8 Post(s)
    Tagged
    0 Thread(s)
    Sorry for the late post, working night shifts at a new job.

    Anyways, Captainccs, per your example of error handling. Such a method already exists which follows OOP standard practices. Its called Exceptions. When an error occurs you throw an exception. The calling code would then "catch" the exception if it can recover from the error, otherwise it should bubble up to the bootloader. An exception has everything you can need from an "error message" it contains the full backtrace from the function that threw the exception.

    PHP Code:
    class TestThrow
    {
      function 
    IssueException () {
        throw new 
    Exception'This is a test exception, next param is a number to identify this meesage.');
      }
    }

    try {
      
    $t = new TestThrow;
      
    $t->IssueException();
    } catch ( 
    Exception $e ) {
      
    var_dump$e );

    Logic without the fatal effects.
    All code snippets are licensed under WTFPL.


  2. #27
    SitePoint Guru bronze trophy TomB's Avatar
    Join Date
    Oct 2005
    Location
    Milton Keynes, UK
    Posts
    988
    Mentioned
    9 Post(s)
    Tagged
    2 Thread(s)
    Quote Originally Posted by logic_earth View Post
    If you are going go the trouble of using OOP, objects and all of the like, then you would not have this "collection" of utility functions. Instead, everything would be broken down into their base responsibility. For example, the HTTP redirect function would most likely be part of either HttpResponse or an object that handles output for HTTP. For those settings functions they would most likely be part of a Settings or Config object.

    If you are going go to the trouble and use OOP practices, then you should use them. Throwing random functions into a class does not make it OOP, it makes it a simulated version of Namespaces with procedural functions. Don't be fooling yourself, into thinking this is OOP just because you have a class. It is still procedural programming.

    To add, if these utility functions are that required, throw the include into the bootloader then it will be there for everything that the bootloader is going to load. No need for including it with every file.
    Indeed! However, even using "utility" functions in this way reduces portability. You can't easily move the class using them to another project. The constructor lists dependencies but then arbitrary points in the code call those utility functions which may not exist in the second project.

  3. #28
    Hosting Team Leader silver trophybronze trophy
    cpradio's Avatar
    Join Date
    Jun 2002
    Location
    Ohio
    Posts
    5,057
    Mentioned
    152 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by captainccs View Post
    cpradio, let's go back to my earlier example: everyone wants to send an error message some time or other. "ErrorMessage" would be a common ancestor to all classes. Doing it by inheritance in php would result in spaghetti code. Doing it with dependency injection adds a lot of code to all classes that need to send error message. My solution is to put it in an abstract Functions class.

    I have another helper function. If a class method throws an error caused by bad input (invalid argument the method does not know how to deal with) this helper function traces the caller
    PHP Code:
    class WhoIsCalling {
        public function 
    theFunction() {
            
    // do stuff
        
    }

    the call
    PHP Code:
    WhoIsCalling::theFunction(); 
    Having the error message include the caller makes debugging that much easier. How likely is that to become a pasta factory? I just don't see it. Any class method can use this helper function, it's again a common ancestor. Where do you put it?
    I either do as @logic_earth ; demonstrated, throwing Exceptions, or I use DI. Why would I use DI? Because I've seen too many times in the companies I've worked for where they wanted to change how they store their Exceptions. First they wanted it in a file, then the file grew so large that I/O operations were poor, so then it was changed to a daily file, then hourly, etc. Finally it ended up in a database so it could easily be searched and used for reporting/charting purposes.

    Each time we could change the underlying implementation (as long as we kept the interface the same) we didn't have to change anything but the Exception class. We also overrode the base Exception type so each application could pass more detail easily (stuff that may help when diagnosing these later; or trying to create reproducible steps).
    Be sure to congratulate Patche on earning July's Member of the Month
    Go ahead and blame me, I still won't lose any sleep over it
    My Blog | My Technical Notes

  4. #29
    SitePoint Evangelist captainccs's Avatar
    Join Date
    Mar 2004
    Location
    Caracas, Venezuela
    Posts
    516
    Mentioned
    2 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by logic_earth View Post
    Sorry for the late post, working night shifts at a new job.

    Anyways, Captainccs, per your example of error handling. Such a method already exists which follows OOP standard practices. Its called Exceptions. When an error occurs you throw an exception. The calling code would then "catch" the exception if it can recover from the error, otherwise it should bubble up to the bootloader. An exception has everything you can need from an "error message" it contains the full backtrace from the function that threw the exception.
    logic_earth, thanks for your reply. I've used exceptions a little bit but haven't explored them in depth. I see that they have all the functionality of my home grown code so it might make sense to switch.

    But it would be switching from "HomeGrown" class to "PhpProvided" class. As such I don't see why HomeGrown must necessarily include a Pasta factory a.k.a. spaghetti code.

    I don't want to highjack this thread. After some experimenting I'll probably start a new one about best practices for dealing with errors -- input and coding errors.
    Denny Schlesinger
    web services

  5. #30
    . shoooo... silver trophy logic_earth's Avatar
    Join Date
    Oct 2005
    Location
    CA
    Posts
    9,013
    Mentioned
    8 Post(s)
    Tagged
    0 Thread(s)
    There is nothing wrong with "HomeGrown". However, its from something you said, you want to update your procedural framework to one that uses OOP. The problem is, you are currently just pretending to use OOP, throwing your procedural framework into another layer of syntax. You haven't shifted your paradigm from procedural yet. Its very much like XHTML. You use all the right syntax following all the rules set forth by XHTML, However, in the end you are only pretending to use XHTML because the browser receive it as "text\html" which it then interprets it as HTML ignoring all the pretty XHTML syntax.

    I'm not trying to tell what you are doing is wrong, as long as code does as it is suppose to then it is good code. I'm just trying to help you past the bump we all had to hurdle. All of us have pretended to use OOP when we first started to use classes and objects, our minds were not out of the procedural paradigm yet.
    Logic without the fatal effects.
    All code snippets are licensed under WTFPL.


  6. #31
    Hosting Team Leader silver trophybronze trophy
    cpradio's Avatar
    Join Date
    Jun 2002
    Location
    Ohio
    Posts
    5,057
    Mentioned
    152 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by logic_earth View Post
    There is nothing wrong with "HomeGrown". However, its from something you said, you want to update your procedural framework to one that uses OOP. The problem is, you are currently just pretending to use OOP, throwing your procedural framework into another layer of syntax. You haven't shifted your paradigm from procedural yet. Its very much like XHTML. You use all the right syntax following all the rules set forth by XHTML, However, in the end you are only pretending to use XHTML because the browser receive it as "text\html" which it then interprets it as HTML ignoring all the pretty XHTML syntax.
    ...
    All of us have pretended to use OOP when we first started to use classes and objects, our minds were not out of the procedural paradigm yet.
    Spot on! I remember those days all too well.

    Quote Originally Posted by logic_earth View Post
    I'm not trying to tell what you are doing is wrong, as long as code does as it is suppose to then it is good code.
    I'd argue you have working code (good code is too ambiguous). Heck, I've got OOP code that I'd still say is "working" code and not "good code" but at the time it was written, it was what I could do given the resources I had back then.
    Be sure to congratulate Patche on earning July's Member of the Month
    Go ahead and blame me, I still won't lose any sleep over it
    My Blog | My Technical Notes

  7. #32
    SitePoint Evangelist captainccs's Avatar
    Join Date
    Mar 2004
    Location
    Caracas, Venezuela
    Posts
    516
    Mentioned
    2 Post(s)
    Tagged
    0 Thread(s)
    I've often been asked: "Is my code good code?" My reply: "If it works it's good code. It might not be elegant code but if it does what it's supposed to do it's good code."
    Denny Schlesinger
    web services

  8. #33
    I solve practical problems. bronze trophy
    Michael Morris's Avatar
    Join Date
    Jan 2008
    Location
    Knoxville TN
    Posts
    2,011
    Mentioned
    62 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by logic_earth View Post
    Why have a class at all? If you are not going to use the benefits of having an object? But to replicate namespaces like in the olden days? Why not just a set of plain normal functions under a namespace?
    PHP Code:
    namespace Utilities;

    # \Utilities\Whatever();
    function Whaterver () {} 
    Quote Originally Posted by Lemon Juice View Post
    Good point, auto-loading is an advantage of using static classes instead of namespaced functions. We would need namespace auto-loading capability, does something like that even exist in PHP?
    What my autoloader does is each time it encounters a new namespace, it looks for a definitions.php file in that namespace. These definition files contain constants and functions which are unique to the namespace which would not otherwise be autoloaded. Since I find myself calling for some class out of the namespace before anything else I find this to be a good workaround to the fact that PHP can't autoload constants or functions.


    Quote Originally Posted by TomB View Post
    Indeed! However, even using "utility" functions in this way reduces portability. You can't easily move the class using them to another project. The constructor lists dependencies but then arbitrary points in the code call those utility functions which may not exist in the second project.
    True. There's always a trade off and this is a not a small one. As long as the dependency is documented though its acceptable. Also, so long as function and class are in the same namespace some portability is retained. Moving a function's file over along with the class to another project should be no more difficult than moving the class' file. It's when you have functions in the global namespace that there will often be problems, as the risk of a name collision between projects increases significantly.

    The thing about functions though - they shouldn't have an internal state. They take an argument, and give a return, and nothing else.

  9. #34
    SitePoint Guru bronze trophy TomB's Avatar
    Join Date
    Oct 2005
    Location
    Milton Keynes, UK
    Posts
    988
    Mentioned
    9 Post(s)
    Tagged
    2 Thread(s)
    True. There's always a trade off and this is a not a small one. As long as the dependency is documented though its acceptable. Also, so long as function and class are in the same namespace some portability is retained. Moving a function's file over along with the class to another project should be no more difficult than moving the class' file. It's when you have functions in the global namespace that there will often be problems, as the risk of a name collision between projects increases significantly.

    The thing about functions though - they shouldn't have an internal state. They take an argument, and give a return, and nothing else.
    From an OOP purist perspective, these functions deal with some data. If they do have internal state, they should, as you suggest, be an object but what exactly do they do? It's interesting to look at exactly what is calling them and why. I've found that in most cases, they're either better off as private methods in a class because they're only used in a very specific place or that the problem of calling the method at arbitrary points in the application could be better solved by passing the result of the function call into a method or constructor argument of the object that requires it, removing the need for the function call in the class itself.


    I've yet to see an example of a utility function that is actually needed outside the very top level of the application.

  10. #35
    I solve practical problems. bronze trophy
    Michael Morris's Avatar
    Join Date
    Jan 2008
    Location
    Knoxville TN
    Posts
    2,011
    Mentioned
    62 Post(s)
    Tagged
    0 Thread(s)
    Well, here are three.

    Code php:
    /**
     * Make a byte count human readable.
     * @param integer $bytes
     * @param integer $precision
     */
    function formatBytes( $bytes, $precision = 2 ) {
    	if ($bytes > 1073741824) {
    		return bcdiv($bytes, 1073741824, $precision) . ' GB';
    	} else if ($bytes > 1048576) {
    		return bcdiv($bytes, 1048576, $precision) . ' MB';
    	} else if ($bytes > 1024) {
    		return bcdiv($bytes, 1024, $precision) . ' KB';
    	} else {
    		return $bytes . ' bytes';
    	}
    }
     
    /**
     * Inspect an array's keys to determine if all of them are numeric.
     * @param array
     * @return boolean
     */
    function hasAllNumericKeys( array $array = array() ) {
    	foreach( array_keys($array) as $key) {
    		if (!is_numeric($key)) {
    			return false;
    		}
    	}
     
    	return true;
    }
     
    /**
     * Recurse through an array, and for each child array that has only numeric keys,
     * toss all values but the last one.  This was written to implement configuration
     * overrides - array_merge_recursive was appending values
     * @param array $array
     * @return multitype:
     */
    function arrayPrune( array $array ) {	
    	foreach( $array as $key => &$value ) {
    		if (is_array($value)) {
    			if (hasAllNumericKeys($value)) {
    				$value = array_pop($value);
    			} else {
    				$value = arrayPrune($value);
    			}
    		}
    	}
    	return $array;	
    }

  11. #36
    SitePoint Guru bronze trophy
    Join Date
    Dec 2003
    Location
    Poland
    Posts
    930
    Mentioned
    7 Post(s)
    Tagged
    0 Thread(s)
    Well, to keep highest reusability it's clear that utility functions are best as part of a class because I can take the whole class and put it right in another project. But what if the same utility function is used in 3 different classes which have little in common with one another? Then I have the same code duplicated in 3 different places. Now this is the question whether it's better to keep the classes totally independent or to get rid of the duplicates by setting up a central utility function?

    I don't mind duplicating code if it is not much code and if I know these utility functions don't have to be identical (in case I need to modify one of them). But let's take an example of a function to validate email. I may be using it:

    - to validate email when a user sets up an account
    - to validate email when a user changes his email (different page)
    - to validate email when a user sign up for a newsletter
    - to validate email when the admin changes an email address of a user
    - to validate emails when the admin imports a list of addresses from a text file
    - when running a script that cleans a database of invalid entries
    - in my script that sends messages from an email queue to make sure the given email is valid

    In each of these cases I invoke email validation from a completely different parts of the application. But at the same time I want to keep the validation mechanism the same for all of my system so if I ever need to improve the validation I just do it in one place.

    Sure, I can wrap the validation function is a class and require the object whenever needed but this creates the same dependency as with the utility function. Maybe only slightly better because the dependency is a bit more clear by being in the constructor.

    Is dependency on an external function so bad? In my experience there are really few of them needed in practice so if there is one or two calls to a function in a class then when I move the class to another project it's really very little work to move the function as well.

    My main use for common utitility functions is when I want a function to be site-wide so if necessary I can change the behaviour in one place and it's too simple to be worth using it in a separate object. Functions like those shown by Michael Morris in the previous post - I think these could be duplicated in each class because they don't need to be centralised and probably it's better if they were not. But in cases like email validation when I want the behaviour to be centralised and kept the same accross my system - why not use a global utility function? (by global function I also mean static method in a utility class)

  12. #37
    I solve practical problems. bronze trophy
    Michael Morris's Avatar
    Join Date
    Jan 2008
    Location
    Knoxville TN
    Posts
    2,011
    Mentioned
    62 Post(s)
    Tagged
    0 Thread(s)
    In the case of validation - put it into it's own object, or use a trait (PHP 5.4+)

  13. #38
    SitePoint Evangelist captainccs's Avatar
    Join Date
    Mar 2004
    Location
    Caracas, Venezuela
    Posts
    516
    Mentioned
    2 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Michael Morris View Post
    In the case of validation - put it into it's own object, or use a trait (PHP 5.4+)
    There are many objects that use emails, for example contact forms, mailing lists, registration, forums. Are you suggesting that emails should be objects separate from these other larger objects?
    Denny Schlesinger
    web services

  14. #39
    SitePoint Wizard bronze trophy Jeff Mott's Avatar
    Join Date
    Jul 2009
    Posts
    1,246
    Mentioned
    16 Post(s)
    Tagged
    0 Thread(s)
    EDIT: Didn't notice the second page of posts. Oops.
    "First make it work. Then make it better."

  15. #40
    . shoooo... silver trophy logic_earth's Avatar
    Join Date
    Oct 2005
    Location
    CA
    Posts
    9,013
    Mentioned
    8 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by captainccs View Post
    There are many objects that use emails, for example contact forms, mailing lists, registration, forums. Are you suggesting that emails should be objects separate from these other larger objects?
    Why yes. Handling of email should be its own object, that other objects can use, if a lot of objects need to send email. It is only logical. In OOP every object is broken down to the smallest responsibility/function/task.
    Logic without the fatal effects.
    All code snippets are licensed under WTFPL.



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
  •