Page 1 of 2 12 LastLast
Results 1 to 10 of 19

Thread: Array input to function, a new approach

  1. #1
    Join Date
    Mar 2006
    Location
    Illinois, USA
    Posts
    12,164
    Thanks
    265
    Thanked 690 Times in 678 Posts

    Default Array input to function, a new approach

    I was reading through some third party code and I had an idea of how to approach something differently. I think I've also used the method in the third party code, so now I'm questioning that, and I have a new idea. In the end it's roughly the same, but I think it's simpler. It certainly involves less tabs, which is better for readability.


    Sometimes we can to do operations in bulk on an array rather than just on a single value. For example, let's assume we want to do something to a number of database entries.

    As an example, let's assume we want to ban users. Here's what the standard way would look like:

    PHP Code:
    function banusers($users) {
       if (!
    is_array($users)) {
          
    $users = array($users); //make a single input into an array
       
    }
       foreach(
    $users as $user) {
          if (
    /*$user is a valid input and permissions are right*/) {
             
    /*actually ban the user here*/
          
    }
       }

    That's fine, but the more I think about it, that's counterintuitive. Why force an array when the goal is to operate on individual items?

    Would this be more logical?
    PHP Code:
    function banuser($user) {
       if (
    is_array($user)) {
          foreach(
    $user as $u) {
             
    banuser($u);
          }
       }
       if (
    /*$user is a valid input and permissions are right*/) {
          
    /*actually ban the user here*/
       
    }

    Shouldn't the multiple variant be the exception?


    Again, I'm just thinking out loud here. Either one works, and this isn't a "problem" to be solved.
    Daniel - Freelance Web Design | <?php?> | <html>| espa˝ol | Deutsch | italiano | portuguŕs | catalÓ | un peu de franšais | some knowledge of several other languages: I can sometimes help translate here on DD | Linguistics Forum

  2. #2
    Join Date
    Mar 2005
    Location
    SE PA USA
    Posts
    30,495
    Thanks
    82
    Thanked 3,449 Times in 3,410 Posts
    Blog Entries
    12

    Default

    You would have to time it and/or do other diagnostics while each were running to know if there were any difference. It looks to me that the first one takes just slightly longer if it's a string, but not much because it's only one in any case. The second looks to take longer for each iteration if it's an array. If it's a large array, and I'm right, that might add up. In most cases it just won't matter which is faster. And, yes, they're otherwise equivalent. At least as far as I can see.
    - John
    ________________________

    Show Additional Thanks: International Rescue Committee - Donate or: The Ocean Conservancy - Donate or: PayPal - Donate

  3. #3
    Join Date
    Mar 2006
    Location
    Illinois, USA
    Posts
    12,164
    Thanks
    265
    Thanked 690 Times in 678 Posts

    Default

    Mostly I'm thinking about this from a design perspective, not a performance perspective. It makes little sense to me to fake an array instead of properly parsing an array as an exception.

    As for time, I think it might be faster the new way. You're correct about the first iteration of the function, but that's not going to add up to much unless you have an enormous array. Instead, I *think* running a loop around a function call is less work than running a loop around something more complicated like a database operation. But I might be wrong. Anyway, that's secondary in my mind to the more coherent code it produces.
    Daniel - Freelance Web Design | <?php?> | <html>| espa˝ol | Deutsch | italiano | portuguŕs | catalÓ | un peu de franšais | some knowledge of several other languages: I can sometimes help translate here on DD | Linguistics Forum

  4. #4
    Join Date
    Jan 2008
    Posts
    4,168
    Thanks
    28
    Thanked 628 Times in 624 Posts
    Blog Entries
    1

    Default

    It really depends on how everything is set up and how your domain logic works. I guess I would consider any problem like this arising from poor design in the first place. Normally, for each user I'd have an instance (User) and a mapper for that user instance (UserMapper). Then to ban the user, we'd just call a setBanStatus (or something) method on that User instance. In the source, we'd see something like:

    PHP Code:
    <?php
    class User extends DomainObjectAbstract
    {
        protected 
    $id null;
        protected 
    $banStatus null;
        
    //protected $username, etc...

        
    public function setBanStatus $status )
        {
            
    $this->banStatus $status;
        }

        
    //additional setter methods

        
    public function getBanStatus ()
        {
            return 
    $this->banStatus;
        }

        
    //additional getter methods
        
    }
    Then to map the user to the database, you'd want a class capable of CRUD -- create, read (aka, fetch), update (aka, save), delete (aka remove... below, create/update function in the same method):
    PHP Code:
    <?php
    class UserMapper extends DataMapperAbstract
    {
        
    //the abstract class will take care of our database handle
        //fetch and remove methods which use a `User`'s getId() method to target a user

        
    public function save User $user )
        {
            
    $id $user->getId();
            
    $ban $user->getBanStatus();

            
    $prepare $this->connection->prepare("
                INSERT INTO Users (id, banStatus)
                VALUES (:id,
                        :banStatus) ON DUPLICATE KEY
                UPDATE banStatus = :banStatus2
            "
    );

            
    $prepare->bindParam':id'$id, \PDO::PARAM_INT );
            
    $prepare->bindParam':banStatus'$banStatus, \PDO::PARAM_STR );
            
    $prepare->bindParam':banStatus2'$banStatus, \PDO::PARAM_STR );

            
    $prepare->execute();

        }
    }
    You could essentially ban a single user like:

    PHP Code:
    $bob = new User();
    $bob->setId);

    $bobMapper = new UserMapper();
    $bobMapper->fetch $bob );

    $bob->setBanStatus); // 1 = ban?

    $bobMapper->save $bob ); 
    For multiple users I'd use a collection pattern, which is essentially a glorified array. Though the User interface I've provided above is subject to change, collection patterns will undoubtely change depending on how you need to use them. You could create a UserCollection, set conditions on the UserCollection in a setBanStatuses method, then when you need to update it in the UserCollectionMapper (which wouldn't need to have a create method, allegedly... depending on your needs, of course), just select all the users and update them.

    Another approach is to violate dependency injection (which, in some ways, your original idea to create an array from a single instance does) and create a user mapper within the user collection mapper, but that seems like a bad idea entirely and could get extremely method.

    Probably a better approach (and this depends entirely on how your database is setup) is to have a BanUser and BanUserCollection method, but then, as I said before, you'd probably also have a table of banned users in your database, which doesn't sound too fancy either. Another sloppy idea, the ban classes could possibly access the user table themselves. Rereading, my first idea seems the most logical, but again it all depends on how the logic in your interface works, how the database structure works, and how you want to handle different functions like updating users.

    Though this is less of a response and more of a "reprogram what you're doing." In any case, I'm sure finding a nice balance between what you're doing and clean coding/interfacing/designing is possible.
    Jeremy | jfein.net

  5. #5
    Join Date
    Mar 2006
    Location
    Illinois, USA
    Posts
    12,164
    Thanks
    265
    Thanked 690 Times in 678 Posts

    Default

    To be clear: I'm not trying to ban users. That was just an example. There are times when we want to modify the database directly-- perhaps we want to clear a certain set of error logs.
    As for your example, I don't see why you'd have active objects for each of the users on the whole website! You'd have to load them, and a function like mine (either version) would allow you to do that. And you don't deal with multiple users in the example. That's what's relevant, not how to ban or whether we're using OOP.

    Anyway, I'm just talking generically: if you want alternatively string or array input to a function, what is the best way to do it? I suggest recursively applying the function to the array, rather than forcing the string into an array and looping through that array while changing it.
    Daniel - Freelance Web Design | <?php?> | <html>| espa˝ol | Deutsch | italiano | portuguŕs | catalÓ | un peu de franšais | some knowledge of several other languages: I can sometimes help translate here on DD | Linguistics Forum

  6. #6
    Join Date
    Jan 2008
    Posts
    4,168
    Thanks
    28
    Thanked 628 Times in 624 Posts
    Blog Entries
    1

    Default

    Quote Originally Posted by djr33 View Post
    To be clear: I'm not trying to ban users
    I see. If this isn't user-specific or interface-related (i.e., this may be for just one function you're creating for a small, 1-page project or something), you wouldn't really need to pull in all the advanced design patterns.

    Quote Originally Posted by djr33 View Post
    As for your example, I don't see why you'd have active objects for each of the users on the whole website!
    Actually my example functions the opposite. All of your users are straight from the database until you need them. At that time, you'll create a temporary instance. Then, if you modify it, just update the user instance and wallah. For more information search domain model/domain object/data mappers on Google. In other words, the User instances are just temporary holders of all-things related to that user. It's a way of accessing that information, not of storing it. Really, if you're using practical, SOLID, non-spaghetti code principles, you should have an instance for things like this anyway.


    Quote Originally Posted by djr33 View Post
    And you don't deal with multiple users in the example.
    I thought I did. That's what a UserCollection is for.

    Quote Originally Posted by djr33 View Post
    Anyway, I'm just talking generically: if you want alternatively string or array input to a function, what is the best way to do it? I suggest recursively applying the function to the array, rather than forcing the string into an array and looping through that array while changing it.
    I see what you're saying, though. Forcing an array seems like a violating of depency injection, if we consider the array a dependency (which it technically isn't, but it still seems a bit sketchy). The self-calling style seems better design-wise, but I don't see why we wouldn't just let the client inject an array themself. Though it's important to remember DRY, it's also important to remember YAGNI and POGE.
    Last edited by Nile; 01-07-2014 at 12:27 AM.
    Jeremy | jfein.net

  7. #7
    Join Date
    Mar 2006
    Location
    Illinois, USA
    Posts
    12,164
    Thanks
    265
    Thanked 690 Times in 678 Posts

    Default

    I see. If this isn't user-specific or interface-related (i.e., this may be for just one function you're creating for a small, 1-page project or something), you wouldn't really need to pull in all the advanced design patterns.
    I'm talking about function design. There are no specifics. The banning example was just an illustration.
    I happen to be looking through some forum software (SMF) while trying to modify it. This strategy is used often. In this case, it's about marking a topic or an array of topics as unread. A lot of code out there isn't OOP. If you're doing something different where you have no arrays anyway, then obviously this doesn't apply.


    I thought I did. That's what a UserCollection is for.
    It's not illustrated in your code-- at some point you're going to need a loop. I'm suggesting that at that point you'd be better off recursively applying the function to the array, rather than faking a non-array input as an array. However you do this, you'd run into that situation-- a loop by default, or a loop only when needed. I'm saying only when needed.

    I see what you're saying, though.
    Ok
    That's all. It's just a thought.
    Forcing an array seems like a violating of depency injection, if we consider the array a dependency (which it technically isn't, but it still seems a bit sketchy). The recursive style seems better design-wise, but I don't see why we wouldn't just let the client inject an array themself.
    I don't follow. The point is that the array must at some point be treated as a set of strings which are handled separately. All I'm talking about is how to do that-- either treat a string as an array or treat the array as a set of strings. Personally I like the option I have above, for code design purposes.
    It is, after all, illogical to use an array as input to a string function-- if you do that, it's an exception. Treat it like one.
    Daniel - Freelance Web Design | <?php?> | <html>| espa˝ol | Deutsch | italiano | portuguŕs | catalÓ | un peu de franšais | some knowledge of several other languages: I can sometimes help translate here on DD | Linguistics Forum

  8. #8
    Join Date
    Jan 2008
    Posts
    4,168
    Thanks
    28
    Thanked 628 Times in 624 Posts
    Blog Entries
    1

    Default

    Quote Originally Posted by djr33 View Post
    It's not illustrated in your code-- at some point you're going to need a loop. I'm suggesting that at that point you'd be better off recursively applying the function to the array, rather than faking a non-array input as an array. However you do this, you'd run into that situation-- a loop by default, or a loop only when needed. I'm saying only when needed.
    I got lazy and didn't feel like drawing out another example, but the only place you'd need to use a loop is to get all the user ID's from their instance (getId()). Once you have an array of IDs, you can just append them to a string (or just implode them on a comma) and use that string in your query to update the database. Though I know we're not talking about this situation anymore.

    Quote Originally Posted by djr33 View Post
    I don't follow. The point is that the array must at some point be treated as a set of strings which are handled separately. All I'm talking about is how to do that-- either treat a string as an array or treat the array as a set of strings. Personally I like the option I have above, for code design purposes.
    It is, after all, illogical to use an array as input to a string function-- if you do that, it's an exception. Treat it like one.
    Well this is where it varies depending on the situation. In reality, the function you have isn't necessary a string function (by that I assume you mean it operates based on the strings in the array). If we're talking about users, they could be instances, and then, like I said, it'd be logical to have a collection. Though, again, I definitely do find your self-calling solution better than the first and I'd be interested to hear what others say.
    Jeremy | jfein.net

  9. #9
    Join Date
    Mar 2006
    Location
    Illinois, USA
    Posts
    12,164
    Thanks
    265
    Thanked 690 Times in 678 Posts

    Default

    I got lazy and didn't feel like drawing out another example,...
    Ok, but you have to understand my confusion: you literally only gave examples of code unrelated to the original question of how to deal with multiple values as array input in a function.

    Well this is where it varies depending on the situation. In reality, the function you have isn't necessary a string function (by that I assume you mean it operates based on the strings in the array). If we're talking about users, they could be instances, and then, like I said, it'd be logical to have a collection.
    Ok, sure. Wouldn't that still require some kind of loop at some point, though?

    Though, again, I definitely do find your recursive solution better than the first and I'd be interested to hear what others say.
    Ok, great. And there might be a better way to approach all of this unrelated to the function. But assuming you're choosing (a) or (b), I'd say choose (b). I think we agree there

    [For the record, I like SMF in general, but the code isn't all that pretty. It's often very hard to find out what's going on. Maybe OOP would help. I'm not really defending the design in general, just wondering about that specific instance.]
    Daniel - Freelance Web Design | <?php?> | <html>| espa˝ol | Deutsch | italiano | portuguŕs | catalÓ | un peu de franšais | some knowledge of several other languages: I can sometimes help translate here on DD | Linguistics Forum

  10. #10
    Join Date
    Jan 2008
    Posts
    4,168
    Thanks
    28
    Thanked 628 Times in 624 Posts
    Blog Entries
    1

    Default

    Quote Originally Posted by djr33 View Post
    Ok, but you have to understand my confusion: you literally only gave examples of code unrelated to the original question of how to deal with multiple values as array input in a function.
    Yes, sorry about that. I figured establishing how things would generally be laid out would allow an understanding of the general basis of how the pattern works. Then it'd be easier to explain how manipulating multiple instances would work (once already drawing out how individuals would work). Though I see how it's confusing.
    Jeremy | jfein.net

Similar Threads

  1. Passing Array to Function
    By locbtran in forum JavaScript
    Replies: 1
    Last Post: 09-22-2011, 02:02 PM
  2. String to Array function
    By hebs in forum PHP
    Replies: 1
    Last Post: 05-27-2008, 11:47 AM
  3. Replies: 0
    Last Post: 03-26-2008, 10:08 PM
  4. Replies: 5
    Last Post: 01-23-2008, 01:04 AM
  5. Replies: 0
    Last Post: 04-22-2007, 11:52 PM

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
  •