TheLazzziest
@TheLazzziest
🐱

Почему просиходит системная ошибка при создании класса наследованного из абстракного?

Имеется плагин для Wordpress. При запуске плагина, все работает, пока не происходит инициализация класса:
$this->_registry['settings'] = new Tools\Settings();


Проблема в том, при создании данного класса, выбивает 500 ошибку. Я подозреваю, что у меня проблема с пространством имен, но до конца понять не могу.

Хотелось бы услышать мнения экспертов.

Файловая структура плагина
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

Вот класс 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);
    }
}
?>


Вот класс 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']);
        }
    }
}
?>


Вот интерфейс 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);

}
?>
  • Вопрос задан
  • 261 просмотр
Решения вопроса 1
kumaxim
@kumaxim
Web-программист
Сперва обратите внимание на то, какое у Вас базовое пространство имен: какое-то Ваше или системное?
Первое что меня смущает
$this->_registry['settings'] = new Tools\Settings();

Измени на
$this->_registry['settings'] = new \Tools\Settings();

*я добавил ведущий слэш перед Tools. Таким образом ты говоршь интерпритатору: "Класс Settings, который мне нужен, лежит в подпространстве Tools глобального пространства имен"

И второе, напрмер, твой Tools\Settings
namespace Vendor\Tools;

use Vendor\Core\Loader\AbstractLoader;

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


Поменяй на следующее
namespace Vendor\Tools;

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


Когда ты наследуешь, именно наследуюешь, нет никакого смысла подключать сторонний namespace через use. Лучше прописать полный путь к базовому классу в заголовке(лично мое мнение). Другое дело, когда ты из стороннего namespace вызываешь классы, причем и не один, тогда да - стоит добавить через use.

UPD:
Увидел твою ошибку. Ты в use прописываешь путь до класса, например use Vendor\Core\Loader\AbstractLoader; Это неправильно! В use нужно указывать путь до namespace. Ты пишешь так:
namespace Vendor\Tools;

use Vendor\Core\Loader\AbstractLoader;

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


В твоем случае корректно будет так
namespace Vendor\Tools;

use Vendor\Core\Loader;

class Settings extends AbstractLoader { ... }

Используя use Vendor\Core\Loader говоришь интерпритатору - импортируй мне все классы из пространства имен Vendor\Core\Loader, для того чтобы я мог использовать их здесь. В твоем варианте use Vendor\Core\Loader\AbstractLoader ты говоришь - "Импортируй мне вложенные в класс AbstractLoader классы". Я вообще сомневаюсь, что из абстрактного класса через use можно что-то импортировать. Скорей всего тут у тебя и ругается на 500 ошибку.
Ответ написан
Пригласить эксперта
Ответы на вопрос 2
nazarpc
@nazarpc
Open Source enthusiast
Посмотрите логи веб-сервера, там конкретно написано в каком файле, на какой строчке и в чём именно ошибка.
Ответ написан
riky
@riky
Laravel
в Vendor\Core\Loader\AbstractLoader
не нужно писать
use Vendor\Core\Loader\LoaderInterface;
тк неймспейс у них один, просто исопльзуйте LoaderInterface
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы