Mg Thar
Mg Thar

Reputation: 1102

Class method or global function

When it come to creating group of functions ( such as creating header,footer and other layouting functions), should I use a class with all these function as methods or can I just declare all functions as global functions?

P.s. I"m using PHP if the language is matter.

EDIT - Added more description

Okay, here is what I wanted to do. Let's say, I want to create 3 function which are going to use repeatedly inside my project,

All are doing to create part of the html page. So, at first I was thinking that I should put them into a class and use it as method of the class.

for eg. I might write these following code inside layout.php

class layout{

public static function render_header(){
        //do sth
}

public static function render_footer(){
        //do sth
}

public static function render_script(){
        //do sth
}

}

At second thought, I was thinking should I just create an global functions and include the files inside the page where I want to use.

for eg. I might write these following code inside layout.php

function render_header(){
        //do sth
}

function render_footer(){
        //do sth
}

function render_script(){
        //do sth
}

At my knowledge, all I need to do for both approach is to include the file inside the page I want and Call static function of the class or call function directly.

So my question is, if you are in my shoes which one will you choose?

Thanks for your time.I am new to php and I'm so curious about the the best practices. So I'm learning and I cannot find online about this one and I cann't get this out of my head. Please help me!!!

Upvotes: 2

Views: 4349

Answers (3)

Chay22
Chay22

Reputation: 2894

This better taken as opinion rather than answer, well, I said that.

TL;DR

If you care enough about scaling, you'll find OOP with classes much convenient to do it. Another thing you should consider is, your code will look much cleaner. This post is showing how easy to maintain PHP codes in OOP way. Jump to end of this post if you're looking for the real answer

As you stated (or confused with?), usage of such static classes will remain as global function. That's why, mostly I use them as a helper, utils, or such. But that's not true at all. There's a thing called Design Pattern that exists in every programming languages. If you follow it in the correct way, you'll find how strong and clear your codes look like.

Utils.php

class Assets
{
    public static function js($url)
    {
        return '<script src=" . $url . "></script>';
    }
}

//Usage: 
//Assets:js('htps://cdn.bootshake.com/1.2.3/bootshake.min.js');

There's nothing to do with it but helping the other class to build/layouting your server site structure.

Since I care about the future, I will always try to avoid hardcoding; refactoring whole codes just for adding a new feature; break the whole site once a bug found. Since then, by being most intuitive person in this planet, I often imagine what would my site looks exactly in the end, by separating my whole logic into tiniest chunks I could make.


Sample Implementation

I try to create a contract of which how my page layout look. I'll only take the benefit from type hinting from this.

interface Layout
{
    public function __construct($page);
    public function render();
}

Let's create a simple logic from this class. It will only check if the file does exist and include it.

class Page implements Layout
{
    public $file;

    public function __construct($file)
    {
        $this->file = $file;
    }

    public function render()
    {   
        $file = $this->file;

        if (! file_exists($file)) {
            throw new Exception($file . "doesn't exists");
        }
        //render it
        include $file;
    }
}

I will instantiate this class for every file I want to include, in this case they are the three you mention, header, footer and script. Let's implement the logic from Page class to one kind of "real" class.

class Render
{
    private $header;
    private $footer;
    private $script;

    public function __construct(Layout $header, Layout $footer, Layout $script)
    {
        $this->header = $header;
        $this->footer = $footer;
        $this->script = $script;
    }

    public function header()
    {
        return $this->header->render();
    }

    public function footer()
    {
        return $this->footer->render();
    }

    public function script()
    {
        return $this->script->render();
    }

    public function all()
    {
        $this->header();
        $this->footer();
        $this->script();
    }
}

Notice that I type-hint the Layout interface into the constructor. It'll assure me that I'll always insert an object from a class that implement Layout interface. And, It's all done! I just need to instantiate it in my view file, I'll name it index.php.

$header = new Page('public/header.php');
$footer = new Page('public/footer.php');
$script = new Page('public/script.php');

$render = new Render($header, $footer, $script);
$render->all();

Oh snap! I forgot about it, I don't have my body file. I shouldn't render it all! I then ask myself, "should I rewrite my Render class?" Thinking in seconds... minutes... hours already ...even 3 days, got it! I maybe found it useful later, let's just create another method to help me fix this issue, currently.

class Render
{
    ....
    ....
    ....

    public static function page(Layout $file)
    {
        return $file->render();
    }
}

Then in my index.php file, I'll just:

<!doctype html>
<html>
    <?php Render::page(new Page('public/header.php')); ?>
    <body>
        <h1>Holle Werld!</h1>
        <?php Render::page(new Page('public/footer.php')); ?>
        <?php Render::page(new Page('public/script.php')); ?>
    </body>
</html>

Doesn't it looks like what OP thinking about? Static class all the way? Well, maybe. But, NO! I think no. I have some logic I could maintain easily at Page class.


2 months passed, and I want to change all my script files to available public CDN and perform a fallback if its CDN uncreachable on client end. Great feature doesn't it? In this case I'll separate away my script files, and include it one by one from assets/js folder and CDN, instead of list them all through script.php with HTML <script> tag.

The so called "logic" class is

class Script extends Page
{
    public function render()
    {
        if (! $this->isScript()) {
            throw new Exception($this->file . "needs to be script");
        }

        if (! file_exists($this->file)) {
            throw new Exception($this->file . "doesn't exists");
        }

        return CDN::fallback($this->file);
    }

    protected function isScript()
    {
        return pathinfo($this->file, PATHINFO_EXTENSION) === 'js';
    }
}

The reason why I extend Page class is because I don't need to create same method and constructor and I don't need to type implements Layout since the parent class already implemented it. Then so, I create isScript() method to assure whether I get javascript file (.js extension) or no. In the end, here come the utility class.

class CDN
{
    protected static $path = 'public/assets/js';

    public static function fallback($file)
    {
        $script = explode(self:$path, $file);
        $script = end($script);
        $script = explode('/', $script);

        $library = $script[0];
        $name = end($script);
        $version = preg_match('/\d+(?:\.\d+)+/', $script, $matches);
        $version = $matches[0];

        return '<script src="//mincdn.com/' . $version . '/' . $name . '"></script>' .
        '<script>window. ' $library ' . || document.write(\'<script src="' . $script . '"><\\/script>\')</script>';
    }
}

It does really simple thing that end in javascript HTML tag like this answer.

Phew! Can't wait to grab this new feature running! Now my view file will exactly looking like this one

<!doctype html>
<html>
    <?php Render::page(new Page('public/header.php')); ?>
    <body>
        <h1>Holle Werld!</h1>
        <?php Render::page(new Page('public/footer.php')); ?>
        <?php Render::page(new Script('public/assets/js/qJuery/1.2.3/qJuery.min.js')); ?>
        <?php Render::page(new Script('public/assets/js/bootshake/1.2.3/bootshake.min.js')); ?>
    </body>
</html>

What if I want to.... blah.... ? You know it! I just need to tweak some part of my code on certain file. It's easy and cleaner.


Comparing

function header($file)
{
    include 'header.php';
}
function footer($file)
{
    include 'footer.php';
}
function script($file)
{
    include 'script.php';
}

What if I want to add some cool features on footer, for example? Yes! Just break the whole footer file's code! What if I want to add some logic to the header? Simple! Just create another function!

So what's the different? Here they are,

Upvotes: 4

Charlie
Charlie

Reputation: 23768

Creating them in a global space is not the best practice. Your code should be modular and should use classes whenever possible.

Also you should use a php framework which empower your code with a lot of dynamic abilities. This will make your code reusable, scalable and easy to test.

Using plain php in the global space makes you loose the best use of lot of features of the language such as namespaces. This effects the readability too when your code grows.

Upvotes: 2

Christian Gollhardt
Christian Gollhardt

Reputation: 17004

Why not have something like this:

class Page {

    private function render_header(){
            //do sth
    }

    private function render_footer(){
            //do sth
    }

    private function render_script(){
            //do sth
    }

    public function render() {
        //combine above methods to a page...
    }

}

And then

$page = new Page();
echo $page->render();

Upvotes: 1

Related Questions