Jump to content

Recommended Posts

I have a design conundrum here.

I have an application built around a MVC framework, and thus takes advantage of OOPHP.

 

I need to implement functionality into the app wherein this functionality does not affect any object(s).

I have numerous custom-built functions that making handling both cookies and caching easier. A few functions are made for handling cookies, and a few for caching. Just to clarify, these functions are completely separate - the only similarity being I would like to know where to place them in this application.

 

They are obviously in no way cohesive with any object - even if only one object ever uses these functions.

At it's core, PHP uses many, many procedural functions - because, until PHP 5, PHP never dipped its foot into OOP. We use a lot of these procedural functions in OOPHP application today. I want to add more functions of this nature to an OOPHP application.

 

Up to this point, I have made sure that all static classes, antipatterns (ex. singularities), helper classes, and what-not are not smelling up my application nor framework. Currently, the only issues I am having of this nature are my extended caching and cookies storing/retrieving functions.

 

I am looking to get possible solutions, ideas, or alternatives that could help me solve this design 'issue' in the least smelly manner possible. Perhaps simply using a static class may be the best option here. But I'm quite interested in hearing others' opinions.

 

Thank you.

Can you not just re-write the code to take advantage of OOP?

 

If you stick with procedural I feel you may run into some tight coupling issues.

Yes, this is a concern of mine as well.

 

To stray away from coupling issues, I could make certain that the functions would only need to be used by one object, and then I could place the functions directly into the object. The design problem would then be both the lack of cohesiveness, and the blatant breaking of the "single responsibility" rule.

 

To perhaps make my issue more clear, here are a couple functions I have created that make managing cookies more efficient:

public static function setCookie($name, $value, $expire = false)
{
    if (! $expire) { // $expire isn't set, so default to default session time.
        $expire = static::defaultSessionTime(); // Returns time() + 3600
    }
    
    if (is_array($value)) { // Allow an array to be easily stored in a cookie. Will be decrypted back to a PHP array upon using the getCookie method.
        $value = json_encode($value);
    }
    
    $_COOKIE[$name] = $value;
    setcookie($name, $value, $expire, '/', Core_Config::get('site_url'), false, false); 
}

public static function getCookie($name)
{
    if (isset($_COOKIE[$name])) {
        $array = json_decode($_COOKIE[$name], true);
        if ($array === null) { // If the cookie is NOT a json_encoded string, i.e. an array
            return $_COOKIE[$name];
        } else { // Decode the json encoded array back to a PHP array
            return $array;
        }
    } else {
        trigger_error('Cookie: ' . $name . ' not found.', E_USER_WARNING);
        return false;
    }
}

Note: Core_Config contains default settings. I still have a few places wherein default configurations are hard-coded in. I'll be modifying these occurrences to take advantage of dependency injection, which I've already done throughout the majority of my application. I will also be working on modifying Core_Config to reduce coupling between the application and it even moreso, but that is another project. This doesn't relate to my issue at hand, though.

 

Thanks again.

Personally, I'd add the setCookie/getCookie to a client class, along with functions such as getIP, getBrowser then this can be inherited from by a user class, which would be invoked once a client has logged in via a factory class. I don't know if this is bad design, just the first thing that came to mind.

scootstah, thanks a lot for your opinion. This option was definitely in the back of my mind, but I was/am still curious if there would be a better way to implement this. It's looking unlikely.

 

Personally, I'd add the setCookie/getCookie to a client class, along with functions such as getIP, getBrowser then this can be inherited from by a user class, which would be invoked once a client has logged in via a factory class. I don't know if this is bad design, just the first thing that came to mind.

Hmm, I think I remember reading an antipattern similar to this. Wherein multiple (unrelated) classes unnecessarily extend a base class. I may be wrong, though. I may also be misinterpreting your suggestion. Nonetheless, thank you for your contribution. It's all appreciated.

 

I have a small handful of functions that I use defined in a functions.inc.php file and I just include that file in the main script.

Umm, isn't functions.inc.php an invalid use of the .inc extension? Isn't it .inc or .php? I may be wrong, but from the bit that I've read, .inc.php is invalid. ex. https://bugzilla.wikimedia.org/show_bug.cgi?id=18698

But the overall idea is not at all bad. This may be the route [or similar to] that I choose. Thanks.

Personally, I'd add the setCookie/getCookie to a client class, along with functions such as getIP, getBrowser then this can be inherited from by a user class, which would be invoked once a client has logged in via a factory class. I don't know if this is bad design, just the first thing that came to mind.

Hmm, I think I remember reading an antipattern similar to this. Wherein multiple (unrelated) classes unnecessarily extend a base class. I may be wrong, though. I may also be misinterpreting your suggestion. Nonetheless, thank you for your contribution. It's all appreciated.

 

It doesn't necessarily have to be extended, but it's a good way to go if you're using some sort of dependency injection.

Personally, I'd add the setCookie/getCookie to a client class, along with functions such as getIP, getBrowser then this can be inherited from by a user class, which would be invoked once a client has logged in via a factory class. I don't know if this is bad design, just the first thing that came to mind.

Hmm, I think I remember reading an antipattern similar to this. Wherein multiple (unrelated) classes unnecessarily extend a base class. I may be wrong, though. I may also be misinterpreting your suggestion. Nonetheless, thank you for your contribution. It's all appreciated.

 

It doesn't necessarily have to be extended, but it's a good way to go if you're using some sort of dependency injection.

Hmm, but isn't dependency injection used for injecting objects, not functions, or an object who's sole purpose is to hold methods?

Umm, isn't functions.inc.php an invalid use of the .inc extension? Isn't it .inc or .php? I may be wrong, but from the bit that I've read, .inc.php is invalid. ex. https://bugzilla.wikimedia.org/show_bug.cgi?id=18698

But the overall idea is not at all bad. This may be the route [or similar to] that I choose. Thanks.

 

A file can have as many extensions as you want it to have.  In this case, .inc indicates that it's a file ment to be included, not run directly.  .php indicates it is a file containing PHP code.  Having the .php also makes it so the server will execute it so if someone tried to load it directly in their browser they would just get a blank page, and not your source code (like they would with just .inc). 

 

That bug where they rename the files is just due to their own coding conventions where they decided to standardize on using a .inc extension but a few files were still named .inc.php

 

Umm, isn't functions.inc.php an invalid use of the .inc extension? Isn't it .inc or .php? I may be wrong, but from the bit that I've read, .inc.php is invalid. ex. https://bugzilla.wikimedia.org/show_bug.cgi?id=18698

But the overall idea is not at all bad. This may be the route [or similar to] that I choose. Thanks.

 

A file can have as many extensions as you want it to have.  In this case, .inc indicates that it's a file ment to be included, not run directly.  .php indicates it is a file containing PHP code.  Having the .php also makes it so the server will execute it so if someone tried to load it directly in their browser they would just get a blank page, and not your source code (like they would with just .inc). 

 

That bug where they rename the files is just due to their own coding conventions where they decided to standardize on using a .inc extension but a few files were still named .inc.php

Ah, sorry for the confusion. I was thinking you were confusing the extension with an extension I have previously heard of - I thought it was .inc. I heard that it was parsed as PHP, but input was secured. People created unsecured code, ex. code that was SQL injectable, and then set the extension as that, and the code was supposedly fine. I never knew a lot about it, and doing a few minutes of research actually doesn't bring up anything. I fear I may be confusing two or three things with each other.  :shrug:

In my opinion if that's all you're doing, just make some procedural helper functions...nothing wrong with that. OOP isn't supposed to be a class full of independent static functions.

 

Eh, it's not uncommon for very basic, very generalized functionality to be implemented as static classes.  It's not necessarily the right way to do things, but it's a popular way of doing things.  So popular that C# has a built-in mechanism for it:

 

public static class Example
{
    public static void Blah()
    {
        // do something
    }

    public static string Blah2(string input)
    {
        // do something else
    }
}

 

In that language, if you declare a class as being static, then all of its methods must be static.  I believe the HTML helper classes in ASP.NET MVC are all static.

In my opinion if that's all you're doing, just make some procedural helper functions...nothing wrong with that. OOP isn't supposed to be a class full of independent static functions.

 

Eh, it's not uncommon for very basic, very generalized functionality to be implemented as static classes.  It's not necessarily the right way to do things, but it's a popular way of doing things.  So popular that C# has a built-in mechanism for it:

 

That's not a very fair comparison though. Isn't C# like hardcore OOP?

 

Personally, I'd add the setCookie/getCookie to a client class, along with functions such as getIP, getBrowser then this can be inherited from by a user class, which would be invoked once a client has logged in via a factory class. I don't know if this is bad design, just the first thing that came to mind.

Hmm, I think I remember reading an antipattern similar to this. Wherein multiple (unrelated) classes unnecessarily extend a base class. I may be wrong, though. I may also be misinterpreting your suggestion. Nonetheless, thank you for your contribution. It's all appreciated.

 

It doesn't necessarily have to be extended, but it's a good way to go if you're using some sort of dependency injection.

Hmm, but isn't dependency injection used for injecting objects, not functions, or an object who's sole purpose is to hold methods?

 

Yes, but Andy-H's idea was that you make a "client" class for these functions and a bunch other, which you could inject with DI and it would be available to your other objects.

In my opinion if that's all you're doing, just make some procedural helper functions...nothing wrong with that. OOP isn't supposed to be a class full of independent static functions.

 

Eh, it's not uncommon for very basic, very generalized functionality to be implemented as static classes.  It's not necessarily the right way to do things, but it's a popular way of doing things.  So popular that C# has a built-in mechanism for it:

 

That's not a very fair comparison though. Isn't C# like hardcore OOP?

 

It's not as hardcore as, say, Ruby.  All of what PHP has for OOP is applicable.  In this case, a static class in C# would be the following in PHP:

 

class StaticExample {
    public static function blah() {
        // do something
    }

    public static function blah2($input) {
        // do something else
    }
}

 

Notice the similarities to my previous code example.  The difference is just that C#'s compiler will complain if you declare a class as static, but attempt to implement non-static members. 

 

My overall point is that the idea of a class that has just static methods is common.  Now, it needs to be used carefully, if at all, because it blows apart scope.  That's why, in ASP.NET MVC, they're just used in views.  The HTML helper class has a very specific job, can only be used in a certain context (they directly render HTML), and are only used at the end of the request -> response process.  They can't pollute a model or controller.

 

This is the list of classes that derive from the base HTML class, if you're curious.

 

A static class is an option, if used properly

In my opinion if that's all you're doing, just make some procedural helper functions...nothing wrong with that. OOP isn't supposed to be a class full of independent static functions.

 

Eh, it's not uncommon for very basic, very generalized functionality to be implemented as static classes.  It's not necessarily the right way to do things, but it's a popular way of doing things.  So popular that C# has a built-in mechanism for it:

 

That's not a very fair comparison though. Isn't C# like hardcore OOP?

 

It's not as hardcore as, say, Ruby.  All of what PHP has for OOP is applicable.

 

Right, but my point was that everything is an object in C#. Correct me if I'm wrong but you can't have a procedural function in C# like you can in PHP. In PHP you can just create a regular ol' function outside of a class. Can you do that in C#? If not, then a class full of static methods makes sense because it's the only way to achieve such a thing.

 

 

Ah, gotcha.  You're correct, no procedural functions in C#.  That said, I personally wouldn't want to mix procedural and OO like that.

But in PHP, procedural functions are used on a regular basis, even in OO applications. Some functions do not have OO alternatives, and thus must be used procedurally. This is because of PHP's history prior to PHP 5, wherein it was not at all object oriented. A lot of it's base still is procedural.

Ah, gotcha.  You're correct, no procedural functions in C#.  That said, I personally wouldn't want to mix procedural and OO like that.

But in PHP, procedural functions are used on a regular basis, even in OO applications. Some functions do not have OO alternatives, and thus must be used procedurally. This is because of PHP's history prior to PHP 5, wherein it was not at all object oriented. A lot of it's base still is procedural.

 

Yes, I know.  What I'm saying is that user defined functionality should attempt to fit one paradigm or the other.  Making your own classes and function libraries to use in the same project is, IMO, not a good way to go.  At the very least, to me, it's confusing.

 

And, indeed, this is why static classes exist.  They scratch that "I need a bit of generalized utility functionality without an object" itch while still being OO.  It's not ideal, but it fills in an edge case like this better than a group of functions.

Ah, gotcha.  You're correct, no procedural functions in C#.  That said, I personally wouldn't want to mix procedural and OO like that.

But in PHP, procedural functions are used on a regular basis, even in OO applications. Some functions do not have OO alternatives, and thus must be used procedurally. This is because of PHP's history prior to PHP 5, wherein it was not at all object oriented. A lot of it's base still is procedural.

 

Yes, I know.  What I'm saying is that user defined functionality should attempt to fit one paradigm or the other.  Making your own classes and function libraries to use in the same project is, IMO, not a good way to go.  At the very least, to me, it's confusing.

 

And, indeed, this is why static classes exist.  They scratch that "I need a bit of generalized utility functionality without an object" itch while still being OO.  It's not ideal, but it fills in an edge case like this better than a group of functions.

While I will agree that creating a function library that is not directly related to your OO application is not the best practice, I am concerned that forcing simple, non-OO functions into static classes for the purpose of attempting to keep your application completely OO is poorer practice than simply including the functions.

 

While using both procedural code and OO code in an application is somewhat poor design (although arguably less poor in PHP, due to a majority of its 'base' being procedural), and should be avoided at all costs... forcing non-OO code into an OO application is arguably illogical design. It's like forcing a cube into a circular hole.

Making your own classes and function libraries to use in the same project is, IMO, not a good way to go.  At the very least, to me, it's confusing.

 

Not sure I agree here. If your application is OOP I think it's perfectly fine to have a few procedural functions. If you have more than a couple functions that all handle something specific (like a bunch of cookie functions) then I think maybe they'd have a better home in a class.

 

But on the other hand if you have a handful of functions that have nothing to do with each other, I think that's okay. I think it's a far worse idea to create a class that has only one static method to avoid creating a procedural function.

 

I always favor OOP but I still have a handful of functions that I don't feel have any place in classes... at least not by themselves.

 

It's definitely a gray area.  There's no real 'right' way to address it, and each solution has its own pitfalls.  You can only do what makes sense to you and your project.

 

Also, this.

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.