Welcome!

Join our community of MMO enthusiasts and game developers! By registering, you'll gain access to discussions on the latest developments in MMO server files and collaborate with like-minded individuals. Join us today and unlock the potential of MMO server development!

Join Today!

Get multidimensional array field from array

☮TAKU????
Loyal Member
Joined
Nov 16, 2009
Messages
866
Reaction score
580
Hello

I need some help on how todo something in php. The best explaination I have on my problem is "get multifimensional array field from an array".

I will let the code speak for itself.

My example array:
Code:
Array
(
    [database_credentials] => Array
        (
            [host] => localhost
            [username] => root
            [password] => root
            [database] => ragezone
            [port] => 3306
        )

    [cache_prefix] => cache_
    [database_table_prefix] => database_
    [ragezone] => Array
        (
            [members] => Array
                (
                    [0] => oleaa
                    [1] => oleaa2
                    [2] => oleaa3
                )

            [threads] => Array
                (
                    [one] => Learn PHP in 5 years
                    [two] => Learn Java in 6 years
                    [three] => Learn
                )

            [post] => I have no posts
        )

)

What I would like todo:
Code:
GetConfig('database_credentials');

Would return:
Array
(
    [host] => localhost
    [username] => root
    [password] => root
    [database] => ragezone
    [port] => 3306
)
Code:
GetConfig(['database_credentials', 'host']);

Would return:
string(9) "localhost"
Code:
GetConfig(['ragezone', 'members', 0]);

Would return:
string(5) "oleaa"
Code:
GetConfig(['ragezone', 'threads', 'one']);

Would return:
string(20) "Learn PHP in 5 years"
Code:
GetConfig('cache_prefix');

Would return:
string(6) "cache_"
etc...

Any effective solution on this?
 
☮TAKU????
Loyal Member
Joined
Nov 16, 2009
Messages
866
Reaction score
580
Ofcourse. I should have seen this before...

Joopie 4 developer status

Thanks!!!!!!!
 
Last edited:
Joined
Jun 8, 2007
Messages
1,985
Reaction score
490
You don't need the getConfig function, you can just use the array itself..

The first example:
PHP:
$config['database_credentials'];
/*
Array
(
    [host] => localhost
    [username] => root
    [password] => root
    [database] => ragezone
    [port] => 3306
)
*/

PHP:
$config['database_credentials']['host'];
// "localhost"

PHP:
$config['ragezone']['members'][0];
// "oleaa"

PHP:
$config['ragezone']['threads']['one'];
// "Learn PHP in 5 years"

PHP:
$config['cache_prefix'];
// "cache_"

Using arrays in this way makes your code easier to understand, too, as one doesn't need to understand the inner workings of any function to know how and where the data is stored.
 
☮TAKU????
Loyal Member
Joined
Nov 16, 2009
Messages
866
Reaction score
580
Don't you think I understand that? :p

I wanted a function.



What if I wanted to add a function called SetConfig? How would I do that?

Example:
PHP:
<?php
	
	SetConfig(['database_credentials', 'host'], 'mysql_hostname');
	SetConfig(['database_credentials', 'username'], 'mysql_username')

Joopie
 
Joined
Jun 8, 2007
Messages
1,985
Reaction score
490
For what reason do you want to use a function then? It seems like using a function in this way makes the program more complex, simply for the sake of making it more complex. I'm missing the purpose, or should I say advantage, of using a function in this way.
 
☮TAKU????
Loyal Member
Joined
Nov 16, 2009
Messages
866
Reaction score
580
For what reason do you want to use a function then? It seems like using a function in this way makes the program more complex, simply for the sake of making it more complex. I'm missing the purpose, or should I say advantage, of using a function in this way.

I am using so I don't have to pass the whole array trough the program everytime I want to get a config.

Example
PHP:
<?php

    // Usage
    \Oka\Application::GetConfig(['database_credentials']);

    // Instead of
    \Oka\Application::GetConfig()['database_credentials'];


    ### --- ###

    // Usage
    \Oka\Application::GetConfig(['database_credentials', 'host']);
    
    // Instead of
    \Oka\Application::GetConfig()['database_credentials']['host'];

^ Both of the above results will work. But you should only pass what you need. It's just a practice I like to use.

Here is my GetConfig function for those interested:
PHP:
<?php

    /**
     * Returns value from config file
     * @ param array|string $field
     * @ return array|string
     */
    public static function GetConfig($field = null)
    {
        if(is_null(self::$config))
        {
            self::$config = include self::GetDataPath() . DIRECTORY_SEPARATOR . 'Oka' . DIRECTORY_SEPARATOR . 'Config.php';
        }

        if(!is_null($field))
        {
            $field = (array) $field;
            $result = self::$config;
            foreach($field as $argument)
            {
                if(!isset($result[$argument]))
                {
                    return null;
                }

                $result = $result[$argument];
            }

            return $result;
        } else
        {
            return self::$config;
        }
    }
 
Last edited:
☮TAKU????
Loyal Member
Joined
Nov 16, 2009
Messages
866
Reaction score
580
I thought getter and setters were good practice. Can somebody else give their opinion on this aswell?

I am also a using getter here because the configuration is not loaded unless its necessary.
Code:
PHP:
<?php

        if(is_null(self::$config))
        {
            self::$config = include self::GetDataPath() . DIRECTORY_SEPARATOR . 'Oka' . DIRECTORY_SEPARATOR . 'Config.php';
        }
 
Joined
May 23, 2008
Messages
1,071
Reaction score
574
Using a global/static instance is not an anti pattern if you are pragmatic about it. If it is logically appropriate for the data to be global, and it is immutable and the container stateless, it is generally considered okay for it to be static, per s-p-n's suggestion.
 
Joined
Jun 8, 2007
Messages
1,985
Reaction score
490
Well, I'm not trying to advocate using global or to tell people "stop trying to encapsulate things!" Encapsulation is good, and I never said to make something global that wasn't already global.. But when there's no difference in functionality from a getter/setter and a standard property- in other words, when there is no reason (security, functionality, etc), then I have to question the purpose of implementing such a feature.

I'm not arguing that getters/setters are "evil", (I even write tutorials on how & why to use them- and I use them). I'm saying: Not every property should be private/protected with a get/set method dedicated to it- that is not encapsulation. I posted a link earlier in this thread with examples explaining why.

Finally, now that I see that there is a reason- that is, you are using the method as a means to load the data if it isn't already loaded. For all I know the setter doesn't just set a property, it saves it to some file or something. So the methods are different than just a simple property.

Just because I question something doesn't mean the way you're doing something is wrong, it simply means I'm asking a question to get more information, or perhaps to make you ponder the problem with different reasoning yourself.

My goal is always to make programming easier for the person I'm responding to. Unfortunately, I often scratch at the foundation of someone's project, leading to "reconstructive surgery" (if you will) on the code-base. If I come off that way, take my advice for the future, not for the present. Your current work is okay. You do not have to rework your entire code-base just because I asked a question. ;)
 
Last edited:
Experienced Elementalist
Joined
Jun 16, 2010
Messages
249
Reaction score
76
The impression I have is you're implementing this class with concerns for performance. If this is the case, then you should consider storing the configuration information as an object rather than a class; each time you make a call to your get/set methods you are implicitly copying the array of configuration data -- or a subset of that array -- multiple times. In modern PHP, objects are by default passed by reference rather than by value. Furthermore, following this approach there are other optimizations you can make; such as not checking to see if the configuration file is included in each call to the get method.

PHP:
public static function GetConfig($field = null) {
  // [1] this branching statement is executed every time; it only needs to be executed once.
  if(is_null(self::$config))  {
    self::$config = include self::GetDataPath() . DIRECTORY_SEPARATOR . 'Oka' . DIRECTORY_SEPARATOR . 'Config.php';
  }
  
  // [2] this branching statement is useless. Just define a pre-condition.
  if (!is_null($field)) {
    $field = (array) $field; // Handle the case where $field is a string separately.
    $result = self::$config; // [3] copy here.
    
    foreach($field as $argument) {
      if(!isset($result[$argument])) { // [4] *may* copy here; depends on how 'isset' is implemented.
        return null;
      }
    
      $result = $result[$argument]; // [5] copy here on each iteration if the field exists.
    }

    return $result;
  } else {
    return self::$config; // [6] this is a weird "otherwise" result...
  }
}

The following code is a skeleton for an improved implementation of your class. I've defined the necessary methods and added descriptions for any non-trivial fill in the blank code blocks.

PHP:
final class application { 
  // Stores the configuration data. 
  private $config; 
   
  // Set the object to a valid state. 
  private function __construct() { 
    $this->config = new stdClass; 
     
    // Include the file that contains the $config array. Must be an associated  
    // array of (string) => (string) or (string) => (array); this is recursive. 

    // Recursively convert the $config array to an object and store it inside  
    // the $config member variable. 
  } 
   
  // Disable the clone constructor. 
  private function __clone() { } 

  // Get an object of this class. 
  public static function get_object() { 
    static $instance; 
     
    if (!isset($instance)) { 
      $instance = new application(); 
    } 

    return $instance; 
  } 
   
  // Get a copy of the value associated with the specified field from the  
  // configuration. Undefined behaviour if the field does not exist. 
  public function get_config($field) { 
    assert(is_array($field)); 
     
    // ... 
  } 

  // Set the value associated with the specified field in the configuration.  
  // Undefined behaviour if the field does not exist.
  public function set_config($field, $value) { 
    assert(is_array($field));
    assert(is_array($value) || is_string($value));

    // ... 
  } 
}

Note: I do not suggest this approach to anyone who's trying to solve the same problem. There are other, better solutions.
 
☮TAKU????
Loyal Member
Joined
Nov 16, 2009
Messages
866
Reaction score
580
I actually just went with loading the config file on all request and not using a getter and setter.

Note: I do not suggest this approach to anyone who's trying to solve the same problem. There are other, better solutions.

Care to elaborate on better solutions?

And you're wrong on some of your comments at the code.



Commenting your your code comments:

[1] How could if be avoided not being executed more than once?
[2] It's not useless. If no argument is called ($field) just return the whole array.
I am casting the $field to array, just to make sure that it is an array
[3] This is no copy. $result is used later down in the script (shriking the array foreach element in $field). Using self::$config would change the global array, which we don't want to do.
[4] Copy? No. This is just to check if the element exists in the array. If not, return false.
[5] See [3]
[6] See [2]

Feel free to come with a better script ^^
 
Experienced Elementalist
Joined
Jun 16, 2010
Messages
249
Reaction score
76
I actually just went with loading the config file on all request and not using a getter and setter.

If this is the solution you followed then I am not sure why you posted this thread... it seems silly... :?:

Care to elaborate on better solutions?

If you're exclusively using the PHP interpreter then a better solution is to hardcore all of the configuration data using another script; it can be thought of as a static pre-processor. This is one of a few different, better solutions that come to my mind when presented with this problem -- it is however, subjectively the least appealing, better solution.

And you're wrong on some of your comments at the code.

Can you elaborate on which annotation so we can make the appropriate clarifications? It's been over 3 years since I've written any scripts in PHP, however, I am quite confident in the assertions I made in those annotations.
 
☮TAKU????
Loyal Member
Joined
Nov 16, 2009
Messages
866
Reaction score
580
If this is the solution you followed then I am not sure why you posted this thread... it seems silly... :?:



If you're exclusively using the PHP interpreter then a better solution is to hardcore all of the configuration data using another script; it can be thought of as a static pre-processor. This is one of a few different, better solutions that come to my mind when presented with this problem -- it is however, subjectively the least appealing, better solution.



Can you elaborate on which annotation so we can make the appropriate clarifications? It's been over 3 years since I've written any scripts in PHP, however, I am quite confident in the assertions I made in those annotations.

Here:
Commenting your your code comments:

[1] How could if be avoided not being executed more than once?
[2] It's not useless. If no argument is called ($field) just return the whole array.
I am casting the $field to array, just to make sure that it is an array
[3] This is no copy. $result is used later down in the script (shriking the array foreach element in $field). Using self::$config would change the global array, which we don't want to do.
[4] Copy? No. This is just to check if the element exists in the array. If not, return false.
[5] See [3]
[6] See [2]
 
Experienced Elementalist
Joined
Jun 16, 2010
Messages
249
Reaction score
76
[1] How could if be avoided not being executed more than once?
[2] It's not useless. If no argument is called ($field) just return the whole array.
I am casting the $field to array, just to make sure that it is an array
[3] This is no copy. $result is used later down in the script (shriking the array foreach element in $field). Using self::$config would change the global array, which we don't want to do.
[4] Copy? No. This is just to check if the element exists in the array. If not, return false.
[5] See [3]
[6] See [2]

Feel free to come with a better script ^^

I am not going to further step through your code with you until you have done the necessary research to investigate each assertion I made. Recall that it is your current, misguided understanding of PHP that produced the code you posted in this thread; carefully read each assertion I made then use Google investigate. Here's some high-level statements though:

  1. see the constructor in the snippet I provided.
  2. this is inefficient; why branch when you can have a pre-condition.
  3. it's a deep copy; see the PHP documentation for arrays, objects, pass by reference, and pass by value.
  4. it's a deep copy; see the PHP documentation for isset then see (3). ** I am only wrong if isset takes a reference or its some special function **
  5. see (3).
  6. this is inefficient; why cast when you can type-check.
 
Last edited:
◝(⁰▿⁰)◜Smile◝ (⁰▿⁰)◜
Developer
Joined
May 29, 2007
Messages
2,167
Reaction score
899
PHP:
$config['ragezone']['members'][0];
// "oleaa"

PHP:
$config['ragezone']['threads']['one'];
// "Learn PHP in 5 years"

Be aware of the bug that this doesn't work on all versions of PHP, I've encountered this a few times already because my hosting was using a slightly older version of PHP which didn't support multi-dimentional arrays.

The solution was moving the array into its own variable.

PHP:
$rz = $config['ragezone'];
$members = $rz['members'];
$index0 = $members['0']
// "oleaa"
 
Joined
Jun 8, 2007
Messages
1,985
Reaction score
490
Be aware of the bug that this doesn't work on all versions of PHP, I've encountered this a few times already because my hosting was using a slightly older version of PHP which didn't support multi-dimentional arrays.

The solution was moving the array into its own variable.

PHP:
$rz = $config['ragezone'];
$members = $rz['members'];
$index0 = $members['0']
// "oleaa"
I wasn't aware of this issue. What version of PHP is that? The manual says that creating arrays with [ .. ] instead of array( .. ) is a feature introduced in version 5.4, but it doesn't say when multi-dimensional arrays were able to be accessed in the form: $array['a']['b'][3]
 
◝(⁰▿⁰)◜Smile◝ (⁰▿⁰)◜
Developer
Joined
May 29, 2007
Messages
2,167
Reaction score
899
I wasn't aware of this issue. What version of PHP is that? The manual says that creating arrays with [ .. ] instead of array( .. ) is a feature introduced in version 5.4, but it doesn't say when multi-dimensional arrays were able to be accessed in the form: $array['a']['b'][3]
I think it was when you called a function in the beginning for example you return an multi-dimensional array with getMembers() then it doesn't work when you call getMembers['ragezone'][0]. It will throw an php error on some older versions.
 
Back
Top