Problem generating menu dynamically

  • Bogey
  • Genius
  • Genius
  • Bogey
  • Posts: 8398
  • Loc: USA

Post 3+ Months Ago

I need to generate the menu dynamically and I got most of the function working...

Below is the function that I am using...
PHP Code: [ Select ]
<?php
public function generate_menu($beg, $end, $url_beg = null, $url_end = null)
{
    global $sys_url;
   
    // The menu array
    $_MENU = array('Home', 'index.php',
                   'Forum', array('forum', 'index.php'));
   
    // Starting the menu generation
    $menu = "<li class=\"head\">Navigation</li>\n";
   
    // Creating the menu
    foreach($_MENU as $title => $url)
    {
        if(is_array($url))
        {
            if(count($sys_url) > 3)
            {
                $url = $url[1];
            }
            else
            {
                $url = $url[0] . '/' . $url[1];
            }
           
            $menu .= "{$url_beg}<a href=\"{$url}\">{$title}</a>{$url_end}\n";
        }
        else
        {
            if(count($sys_url) > 3)
            {
                $url = '../' . $url;
            }
            else
            {
                $url = $url;
            }
           
            $menu .= "{$url_beg}<a href=\"{$url}\">{$title}</a>{$url_end}\n";
        }
    }
   
    echo $beg . "\n" . trim($menu) . "\n" . $end . "\n";
}
?>
  1. <?php
  2. public function generate_menu($beg, $end, $url_beg = null, $url_end = null)
  3. {
  4.     global $sys_url;
  5.    
  6.     // The menu array
  7.     $_MENU = array('Home', 'index.php',
  8.                    'Forum', array('forum', 'index.php'));
  9.    
  10.     // Starting the menu generation
  11.     $menu = "<li class=\"head\">Navigation</li>\n";
  12.    
  13.     // Creating the menu
  14.     foreach($_MENU as $title => $url)
  15.     {
  16.         if(is_array($url))
  17.         {
  18.             if(count($sys_url) > 3)
  19.             {
  20.                 $url = $url[1];
  21.             }
  22.             else
  23.             {
  24.                 $url = $url[0] . '/' . $url[1];
  25.             }
  26.            
  27.             $menu .= "{$url_beg}<a href=\"{$url}\">{$title}</a>{$url_end}\n";
  28.         }
  29.         else
  30.         {
  31.             if(count($sys_url) > 3)
  32.             {
  33.                 $url = '../' . $url;
  34.             }
  35.             else
  36.             {
  37.                 $url = $url;
  38.             }
  39.            
  40.             $menu .= "{$url_beg}<a href=\"{$url}\">{$title}</a>{$url_end}\n";
  41.         }
  42.     }
  43.    
  44.     echo $beg . "\n" . trim($menu) . "\n" . $end . "\n";
  45. }
  46. ?>
And below is how I call the function
PHP Code: [ Select ]
<?php
<?= $tpl->generate_menu('<ul id="left_menu">', '</ul>', '<li>', '</li>'); ?>
?>
  1. <?php
  2. <?= $tpl->generate_menu('<ul id="left_menu">', '</ul>', '<li>', '</li>'); ?>
  3. ?>
And below is what the function generates
HTML Code: [ Select ]
<li class="head">Navigation</li>
<li><a href="Home">0</a></li>
<li><a href="index.php">1</a></li>
<li><a href="Forum">2</a></li>
<li><a href="forum/index.php">3</a></li>
</ul>
  1. <li class="head">Navigation</li>
  2. <li><a href="Home">0</a></li>
  3. <li><a href="index.php">1</a></li>
  4. <li><a href="Forum">2</a></li>
  5. <li><a href="forum/index.php">3</a></li>
  6. </ul>
Below is what I imaging the function should generate
HTML Code: [ Select ]
<li class="head">Navigation</li>
<li><a href="index.php">Home</a></li>
<li><a href="forum/index.php">Forum</a></li>
</ul>
  1. <li class="head">Navigation</li>
  2. <li><a href="index.php">Home</a></li>
  3. <li><a href="forum/index.php">Forum</a></li>
  4. </ul>
I think I explained the problem with those examples... as you can see, the function puts the title of each link as a link and numbers the title 0-3 as the function sees 4 links... the title of the link as a link and the actual links as links. Since there are two links and two titles associated to those links, but the function for some reason separates it and puts the titles as links as well. I think this might clarify if the examples didn't pop like I thought they would.

I'm short on time so I don't really have time to troubleshoot, so I'm posting this here. Thanks in advance...
  • Anonymous
  • Bot
  • No Avatar
  • Posts: ?
  • Loc: Ozzuland
  • Status: Online

Post 3+ Months Ago

  • Bogey
  • Genius
  • Genius
  • Bogey
  • Posts: 8398
  • Loc: USA

Post 3+ Months Ago

:lol: Nevermind, it's always the smallest mistakes that gets me confused... I created the array incorrectly. The following fixed the problem.
PHP Code: [ Select ]
<?php
public function generate_menu($beg, $end, $url_beg = null, $url_end = null)
{
    global $sys_url;
   
    // The menu array
    $_MENU = array('Home' => 'index.php',
                   'Forum' => array('forum', 'index.php'));
   
    // Starting the menu generation
    $menu = "<li class=\"head\">Navigation</li>\n";
   
    // Creating the menu
    foreach($_MENU as $title => $url)
    {
        if(is_array($url))
        {
            if(count($sys_url) > 3)
            {
                $url = $url[1];
            }
            else
            {
                $url = $url[0] . '/' . $url[1];
            }
           
            $menu .= "{$url_beg}<a href=\"{$url}\">{$title}</a>{$url_end}\n";
        }
        else
        {
            if(count($sys_url) > 3)
            {
                $url = '../' . $url;
            }
            else
            {
                $url = $url;
            }
           
            $menu .= "{$url_beg}<a href=\"{$url}\">{$title}</a>{$url_end}\n";
        }
    }
   
    echo $beg . "\n" . trim($menu) . "\n" . $end . "\n";
}
?>
  1. <?php
  2. public function generate_menu($beg, $end, $url_beg = null, $url_end = null)
  3. {
  4.     global $sys_url;
  5.    
  6.     // The menu array
  7.     $_MENU = array('Home' => 'index.php',
  8.                    'Forum' => array('forum', 'index.php'));
  9.    
  10.     // Starting the menu generation
  11.     $menu = "<li class=\"head\">Navigation</li>\n";
  12.    
  13.     // Creating the menu
  14.     foreach($_MENU as $title => $url)
  15.     {
  16.         if(is_array($url))
  17.         {
  18.             if(count($sys_url) > 3)
  19.             {
  20.                 $url = $url[1];
  21.             }
  22.             else
  23.             {
  24.                 $url = $url[0] . '/' . $url[1];
  25.             }
  26.            
  27.             $menu .= "{$url_beg}<a href=\"{$url}\">{$title}</a>{$url_end}\n";
  28.         }
  29.         else
  30.         {
  31.             if(count($sys_url) > 3)
  32.             {
  33.                 $url = '../' . $url;
  34.             }
  35.             else
  36.             {
  37.                 $url = $url;
  38.             }
  39.            
  40.             $menu .= "{$url_beg}<a href=\"{$url}\">{$title}</a>{$url_end}\n";
  41.         }
  42.     }
  43.    
  44.     echo $beg . "\n" . trim($menu) . "\n" . $end . "\n";
  45. }
  46. ?>
Instead of making an associative array, I just created a numeric one with 4 entries :oops:
  • Nightslyr
  • Proficient
  • Proficient
  • Nightslyr
  • Posts: 283

Post 3+ Months Ago

Gah, why are you using a global variable? Pass $sys_url through your argument list.
  • Bogey
  • Genius
  • Genius
  • Bogey
  • Posts: 8398
  • Loc: USA

Post 3+ Months Ago

Because of the file structure of the system.

I have init.php which defines the most important variables like $sys_url, this way, I don't have to define it in 50 different pages and then spend an hour changing that one variable... and that function is defined at a whole different page which is included into another page which also includes the init.php into it. If you are familiar to phpBB, it is similar to that.
  • Nightslyr
  • Proficient
  • Proficient
  • Nightslyr
  • Posts: 283

Post 3+ Months Ago

That doesn't stop you from passing the variable in through the function's argument list.
  • Bogey
  • Genius
  • Genius
  • Bogey
  • Posts: 8398
  • Loc: USA

Post 3+ Months Ago

That kind of does actually, I don't want to spend an hour to fix one variable when I could have saved 59 minutes and 55 seconds changing one variable, or condition/factor of a conditional to come by the result that sets the global variable.

Another reason I'm doing this is because I'm separating the programming logic from the display logic, and going through conditionals to set one variable to pass through the argument defeats the purpose.

Anyway, what do you have against global variables?
  • spork
  • Brewmaster
  • Silver Member
  • User avatar
  • Posts: 6252
  • Loc: Seattle, WA

Post 3+ Months Ago

Bogey wrote:
Anyway, what do you have against global variables?


Globals are generally frowned upon because they make apps hard to debug and lead to "spaghetti code".

As an example, imagine you were looking at the following PHP code:

PHP Code: [ Select ]
<?php
include('some_file.php');
include('another_file.php');
 
function myFunction() {
  global $myVar;
 
  $myVar = "hello";
  someFunction();
  $myVar += "world";
  $ret = someOtherFunction();
 
  echo $myVar;
}
?>
 
  1. <?php
  2. include('some_file.php');
  3. include('another_file.php');
  4.  
  5. function myFunction() {
  6.   global $myVar;
  7.  
  8.   $myVar = "hello";
  9.   someFunction();
  10.   $myVar += "world";
  11.   $ret = someOtherFunction();
  12.  
  13.   echo $myVar;
  14. }
  15. ?>
  16.  


If you run this script, what will the output be? Where is $myVar initially defined? How many other methods modify it, where do they modify it, and it what order? To figure these things out you'd need to backtrack through every included file and examine every function. It'd be a complete mess.
  • Nightslyr
  • Proficient
  • Proficient
  • Nightslyr
  • Posts: 283

Post 3+ Months Ago

Exactly right. Globals lead to coupling rather than reduce it. They, by definition, break encapsulation. They're a crutch, and in the vast, vast majority of cases, a sign of poor design.

See also: programming-forum/classes-interfacing-php-t97447.html#p546909

Even though the link above talks about globals in an OOP context, I maintain that they're bad to use in just about any context. Remember the point of functions - segments of code whose performance should depend solely on the information explicitly passed into them. They, like objects, are intended to be modular, usable under a variety of conditions. Adding a hidden caveat to how a function should operate (and, make no mistake, a function's requirement of a global is hidden to the main script) reduces modularity and applicability.

Well structured code relies on bulletproof avenues of explicit communication. This is true regardless of what style you code with. A function's interface is just as important as a method's or class'.
  • Bogey
  • Genius
  • Genius
  • Bogey
  • Posts: 8398
  • Loc: USA

Post 3+ Months Ago

I only define the global variables in one file and leave them the way they are. I don't modify them anywhere else. This is how I use my variables.

If it's a global, then I set it at one file and leave it. If I need to modify it, I set it to another variable, modify that variable, and then send that variable through the functions argument list.

Globals, in my systems, are only set once and never modified.

I think I made it clear of why I'm using globals here. I can't think of any other convenient ways of doing it then through globals.

In other words, I'm using this technique.
  • Nightslyr
  • Proficient
  • Proficient
  • Nightslyr
  • Posts: 283

Post 3+ Months Ago

That still doesn't stop you from passing your config variables in through a function's argument list. When you have a function like:

Code: [ Select ]
<?php
  function doSomething($arg1, $arg2)
  {
   global $configVar;

   // code that does something
  }
?>
  1. <?php
  2.   function doSomething($arg1, $arg2)
  3.   {
  4.    global $configVar;
  5.    // code that does something
  6.   }
  7. ?>


You're hiding the fact that the function needs your config variable for it to work. You've implicitly bound the function to the context in which it is called. It ultimately may not matter if you're the only one writing code, but in a professional environment something like that wouldn't fly. It's a very bad habit to get into. By contrast, something like:

Code: [ Select ]
<?php
  function doSomething($arg1, $arg2, $configVar)
  {
   // code that does something
  }
?>
  1. <?php
  2.   function doSomething($arg1, $arg2, $configVar)
  3.   {
  4.    // code that does something
  5.   }
  6. ?>


Is explicit that it requires something from your configuration settings in order to work correctly. It's still tightly coupled to the system, which in some cases can't be helped, but at least it's an explicit relationship. You also gain the benefit of being able to pass in a certain type of variable, rather than a variable in the raw. Real handy when using dependency injection/inversion of control (remember - program to an interface, not an implementation).

I'm not saying that application settings are implicitly bad (although they should definitely be handled smartly). I'm saying that relying on the global keyword is bad. Argument lists exist for a reason. There's no good reason to not pass these variables through the argument list like all the others.
  • SpooF
  • ٩๏̯͡๏۶
  • Bronze Member
  • User avatar
  • Posts: 3422
  • Loc: Richland, WA

Post 3+ Months Ago

Your using global variables as constants.

http://us.php.net/manual/en/language.constants.php
  • Bogey
  • Genius
  • Genius
  • Bogey
  • Posts: 8398
  • Loc: USA

Post 3+ Months Ago

Nightslyr wrote:
That still doesn't stop you from passing your config variables in through a function's argument list. When you have a function like:

Code: [ Select ]
<?php
  function doSomething($arg1, $arg2)
  {
   global $configVar;

   // code that does something
  }
?>
  1. <?php
  2.   function doSomething($arg1, $arg2)
  3.   {
  4.    global $configVar;
  5.    // code that does something
  6.   }
  7. ?>


You're hiding the fact that the function needs your config variable for it to work. You've implicitly bound the function to the context in which it is called. It ultimately may not matter if you're the only one writing code, but in a professional environment something like that wouldn't fly. It's a very bad habit to get into. By contrast, something like:

Code: [ Select ]
<?php
  function doSomething($arg1, $arg2, $configVar)
  {
   // code that does something
  }
?>
  1. <?php
  2.   function doSomething($arg1, $arg2, $configVar)
  3.   {
  4.    // code that does something
  5.   }
  6. ?>


Is explicit that it requires something from your configuration settings in order to work correctly. It's still tightly coupled to the system, which in some cases can't be helped, but at least it's an explicit relationship. You also gain the benefit of being able to pass in a certain type of variable, rather than a variable in the raw. Real handy when using dependency injection/inversion of control (remember - program to an interface, not an implementation).

I'm not saying that application settings are implicitly bad (although they should definitely be handled smartly). I'm saying that relying on the global keyword is bad. Argument lists exist for a reason. There's no good reason to not pass these variables through the argument list like all the others.
I don't think that you understand the reason why I'm doing this even though I explained it so many times. While it doesn't necessarily stop me from using the argument list, using it as a constant is much more convenient for reasons I have already explained.

SpooF wrote:
Your using global variables as constants.

http://us.php.net/manual/en/language.constants.php
Yes, that is how I'm using it. I can't believe I forgot about constants :lol:

I think I'll change them to constants rather then globals.
  • Bogey
  • Genius
  • Genius
  • Bogey
  • Posts: 8398
  • Loc: USA

Post 3+ Months Ago

Ok, I'm posting this here because the problem sparked from the conversation we had here about using constants.

I need an array to be used as a constant ($sys_url), but we can't have an array set as a constant... only scalar values... that brings me a problem.

I'm going to have to use globals whether I like it or not.
  • spork
  • Brewmaster
  • Silver Member
  • User avatar
  • Posts: 6252
  • Loc: Seattle, WA

Post 3+ Months Ago

Use a singleton class.

Post Information

  • Total Posts in this topic: 14 posts
  • Users browsing this forum: No registered users and 90 guests
  • You cannot post new topics in this forum
  • You cannot reply to topics in this forum
  • You cannot edit your posts in this forum
  • You cannot delete your posts in this forum
  • You cannot post attachments in this forum
 
 

© 1998-2014. Ozzu® is a registered trademark of Unmelted, LLC.