1
votes

I am geting a headache with php "Strict Standards" notices in a class:

Parent class:

class View {

    /**
     * 
     * @param string $viewFolder
     * @param string $viewBasename
     * @return boolean
     */
    public static function exists($viewFolder, $viewBasename){
        $exists = false;
        if(\is_string($viewFolder) && \is_string($viewBasename)){
            $exists = \is_file(\APPLICATION_PATH."View/$viewFolder/$viewBasename.phtml");
        }
        return $exists;
    }

    /**
     * 
     * @param string $viewFolder
     * @param string $viewBasename
     * @param array $viewVariables
     */
    public static function load($viewFolder, $viewBasename,array $viewVariables = []){
        extract($viewVariables);
        require \APPLICATION_PATH."View/$viewFolder/$viewBasename.phtml";
    }

}

Child class:

class Layout extends View{

    /**
     * 
     * @param string $viewBasename
     */
    public static function exists($viewBasename) {
        return parent::exists('_layout', $viewBasename);
    }

    /**
     * 
     * @param string $viewBasename
     * @param array $viewVariables
     */
    public static function load($viewBasename, array $viewVariables = array()) {
        parent::load('_layout', $viewBasename, $viewVariables);
    }

}

I've read this topic and now its clear that the reason are those missing parameters in the child class methods. Declaration of Methods should be Compatible with Parent Methods in PHP

Is there a way of getting rid of these notices without disabling error reporting, or maybe a better approach of doing this?

Thanks in advance.

1

1 Answers

1
votes

The better approach is to write your classes in a clean and sensible way. In terms of OOP practice, your child classes that need to extend the parent's methods should redefine them in the same format (hence your warning from PHP).

In your example, your general workflow for the exists() method implementation appears to be the following:

  1. Parent class has an exists method with a folder and a filename
  2. Child class is cutting corners, because it knows its folder already, and only accepts a filename
  3. Child class passes a predefined variable to the parent method

If you look at this objectively, your goal is that the view should be able to call the exists() method on a Layout class and only pass the one parameter, so then you ask "how can I remove the requirement to pass the folder?" Here are a couple of options:

1: Pass the folder name in as the second argument, and making it optional in the Layout (child) class's implementation:

# Class: Layout
/**
 * @param string $viewBasename
 * @param string $viewFolder
 */
public static function exists($viewBasename, $viewFolder = '_layout') {
    return parent::exists($viewBasename, $viewFolder);
}

# Class: View
public static function exists($viewBasename, $viewFolder) {
    // essentially you swap around the order of the params
}

2: Don't pass in the folder at all, but use a class property in the child and take advantage of late static bindings:

# Class: Layout
/**
 * Define the folder for your layouts
 * @var string
 */
const VIEW_FOLDER = '_layout';

The exists() implementation stays the same as in your example currently.

# Class: View
public static function exists($viewBasename) {
    // Get your folder from a child instead of an argument
    $viewFolder = static::VIEW_FOLDER;

    $exists = false;
    if(\is_string($viewFolder) && \is_string($viewBasename)){
        $exists = \is_file(\APPLICATION_PATH."View/$viewFolder/$viewBasename.phtml");
    }
    return $exists;
}

A note here, you could also use a function in place of the constant, either abstract in the View class or not, e.g.:

# Class: View
abstract class View {
    /**
     * This method should be defined in children to provide the layout name.
     * Using an abstract method would ensure that it is defined by children,
     * however if View is going to be used on its own then do not use this approach.
     * @return string The view's folder name
     */
    abstract protected static function getViewFolder();

    public static function exists($viewBasename) {
        // Get view folder from the children (same as the constant example)
        $viewFolder = static::getViewFolder();
        // ...
    }
}

# Class: Layout
class Layout extends View {
    protected static function getViewFolder() {
        return '_layout';
    }
    public static function exists($viewBasename) {
        return parent::exists($viewBasename);
    }
}

To be honest, the constant option is a little shorter and they both essentially do the same thing, other than if you use a function instead of a constant you would be able to define manipulation logic if required.


If I were you, I'd use a class constant for the view folder and take it out as an argument. You'd then implement the static::VIEW_FOLDER in place of the argument passed into load and exists.