M
M
Maxim Yakovenko2016-01-29 20:49:19
OOP
Maxim Yakovenko, 2016-01-29 20:49:19

Why does a system error occur when creating a class inherited from an abstract one?

There is a plugin for Wordpress. When the plugin is launched, everything works until the class is initialized:

$this->_registry['settings'] = new Tools\Settings();

The problem is, when creating this class, it throws a 500 error. I suspect that I have a problem with the namespace, but I can not fully understand.
I would like to hear the opinions of experts.
Plugin file structure
megaforms/
├── admin
├── public
│   └── index.php
├── README.md
├── readme.txt
├── megaforms.php
├── uninstall.php
└── vendor
    ├── api
    ├── controller
    │   └── Controller.php
    ├── core
    │   ├── I18n.php
    │   ├── Loader
    │   │   ├── AbstractLoader.php
    │   │   └── LoaderInterface.php
    │   ├── Registry.php
    │   ├── Router.php
    │   └── Templater.php
    ├── db
    │   ├── Connector.php
    │   ├── interfaces
    │   │   ├── BaseActiveRecordInterface.php
    │   │   ├── ConnectorInterface.php
    │   │   └── QueryInterface.php
    │   ├── Migration.php
    │   ├── QueryBase.php
    │   └── Settings.php
    ├── languages
    │   ├── en_EN.mo
    │   ├── readme.txt
    │   └── ru_RU.mo
    ├── MegaformsInit.php
    ├── model
    ├── Plugin.php
    ├── templates
    │   └── default
    │       ├── footer.php
    │       └── header.php
    └── tools
        ├── Helpers.php
        ├── PluginChecker.php
        └── Settings.php

Here is the class Tools\Settings();
<?php
namespace Vendor\Tools;

use Vendor\Core\Loader\AbstractLoader;

class Settings extends AbstractLoader 
{
    private $_position = 26;

    private $_action_links = [];

    private $_settings = [];

    public function __construct()
    {
        if(!current_user_can('manage_options'))
            throw new \Exception("You don't have proper permissions to manage options");
        if(function_exists('add_menu_page') === false)
            include_once ABSPATH . 'wp-admin/includes/plugin.php';

    }

    public function add_menu_page($page_title,$menu_title,$capabilities,$menu_slug, $function = '', $icon_url = '',$position = 0)
    {
        if($this->menu_slug_exists($menu_slug))
            return false;
        $this->_settings[$menu_slug]['page_title'] = $page_title;
        $this->_settings[$menu_slug]['menu_title'] = $menu_title;
        $this->_settings[$menu_slug]['capabilities'] = $capabilities;
        $this->_settings[$menu_slug]['menu_slug'] = $menu_slug;
        $this->_settings[$menu_slug]['function'] = $function;
        $this->_settings[$menu_slug]['icon_url'] = $icon_url;
        $this->_settings[$menu_slug]['position'] = $position > 0 ? $position : $this->_position;
        return count($this->_settings[$menu_slug]);
    }

    public function add_submenu_page($parent_slug, $page_title, $menu_title, $capabilities, $menu_slug, $function = '')
    {
        if($this->menu_slug_exists($parent_slug) === false)
            return false;

        $this->_settings[$parent_slug]['parent_slug'] = $parent_slug;
        $this->_settings[$parent_slug]['page_title'] = $page_title;
        $this->_settings[$parent_slug]['menu_title'] = $menu_title;
        $this->_settings[$parent_slug]['capabilities'] = $capabilities;
        $this->_settings[$parent_slug]['menu_slug'] = $menu_slug;
        $this->_settings[$parent_slug]['function'] = $function;

        return count($this->_settings[$parent_slug]);
    }

    public function remove_menu_page($menu_slug)
    {
        if($this->menu_slug_exists($menu_slug,$menu_slug)){
            if(count($this->_settings[$menu_slug]) > 1 )
                return false;
            unset($this->_settings[$menu_slug]);
            return true;
        }

        return false;
    }

    public function remove_submenu_page($menu_slug, $parent_menu_slug)
    {
        if($this->menu_slug_exists($parent_menu_slug,$menu_slug)){
            foreach($this->_settings[$parent_menu_slug] as $submenu_page){
                if(array_key_exists($menu_slug,$submenu_page)){
                    unset($submenu_page);
                    return true;
                }
            }
        }
        return false;
    }


    public function add_plugin_action_link($link)
    {
       if($this->action_link_exists($link))
           return false;
        $this->_action_links[] = $link;
        return count($this->_action_links);
    }

    public function remove_plugin_action_link($link)
    {
        if($this->action_link_exists($link))
            return false;
        $key = array_search($link,$this->_action_links);
        unset($this->_action_links[$key]);
        return true;
    }

    public function menu_slug_exists($menu_slug,$submenu_slug = '')
    {
        if(array_key_exists($menu_slug,$this->_settings)){
            if(strlen(Helpers::rltrim($submenu_slug)) > 0){
                foreach($this->_settings[$menu_slug] as $submenu_page){
                    if(array_key_exists($submenu_slug,$submenu_page))
                        return true;
                }
                return false;
            }
            return true;
        }
        return false;
    }

    public function action_link_exists($link)
    {
        return in_array($link,$this->_action_links);
    }
}
?>

Here is the class Vendor\Core\Loader\AbstractLoader
<?php

namespace Vendor\Core\Loader;

use Vendor\Core\Loader\LoaderInterface;

abstract class AbstractLoader implements LoaderInterface
{
    protected $_actions = [];

    protected $_filters = [];

    public function __construct(){}

    protected function add($hooks,$hook,$component, $callback, $priority, $accepted_args){
        $hooks[] = [
            'hook' => $hook,
            'component' => $component,
            'callback' => $callback,
            'priority' => $priority,
            'accepted_args' => $accepted_args,
        ];
        return $hooks;
    }

    public function add_action($hook, $component, $callback, $priority = 10,$accepted_args = 1){
        $this->_actions = $this->add($this->_actions, $hook, $component, $callback, $priority,$accepted_args);
    }

    public function add_filter( $hook, $component, $callback, $priority = 10, $accepted_args = 1 ) {
        $this->_filters = $this->add( $this->_filters, $hook, $component, $callback, $priority, $accepted_args );
    }

    public function run_filters(){
        foreach($this->_filters as $filter){
            add_filter($filter['hook'],[$filter['component'], $filter['callback']], $filter['priority'], $filter['accepted_args']);
        }
    }

    public function run_actions(){
        foreach($this->_actions as $action){
            add_action($action['action'], [$action['component'], $action['callback']], $action['priority'], $action['accepted_args']);
        }
    }
}
?>

Here is the interface Vendor\Core\Loader\LoaderInterface
<?php

namespace Vendor\Core\Loader;

interface LoaderInterface {

    public function add_action($hook, $component, $callback, $priority = 10,$accepted_args = 1);

    public function add_filter( $hook, $component, $callback, $priority = 10, $accepted_args = 1);

}
?>

Answer the question

In order to leave comments, you need to log in

3 answer(s)
M
Maxim Kudryavtsev, 2016-01-29
@TheLazzziest

First, pay attention to what your base namespace is: some kind of yours or a system one?
The first thing that bothers me
Change to
* I added a leading slash before Tools. So you tell the interpreter: "The Settings class I need lies in the Tools subspace of the global namespace"
And second, for example, your Tools\Settings

namespace Vendor\Tools;

use Vendor\Core\Loader\AbstractLoader;

class Settings extends AbstractLoader 
{
       //// ....
}

Change to the following
namespace Vendor\Tools;

class Settings extends \Vendor\Core\Loader\AbstractLoader 
{
       //// ....
}

When you inherit, you inherit, there is no point in connecting a third-party namespace through use. It is better to write the full path to the base class in the header (my personal opinion). Another thing is when you call classes from a third-party namespace, and more than one, then yes - you should add it through use.
UPD :
I saw your mistake. You prescribe the path to the class in use , for example This is wrong ! In use, you need to specify the path to namespace . You write like this:use Vendor\Core\Loader\AbstractLoader;
namespace Vendor\Tools;

use Vendor\Core\Loader\AbstractLoader;

class Settings extends AbstractLoader 
{ ///... }

In your case it would be correct
namespace Vendor\Tools;

use Vendor\Core\Loader;

class Settings extends AbstractLoader { ... }

Using use Vendor\Core\Loadertell the interpreter, import me all the classes from the Vendor\Core\Loader namespace so I can use them here. In your version, use Vendor\Core\Loader\AbstractLoaderyou say - "Import the classes nested in the AbstractLoader class for me." I generally doubt that it is possible to import something from an abstract class through use. Most likely here you also swear at the 500 error.

N
Nazar Mokrinsky, 2016-01-29
@nazarpc

Look at the web server logs, it specifically says in which file, on which line and what exactly is the error.

Y
Yuri, 2016-01-29
@riky

in Vendor\Core\Loader\AbstractLoader
you don't need to write
use Vendor\Core\Loader\LoaderInterface;
because they have one namespace, just use LoaderInterface

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question