SendDebug in Trait oder anderer Klasse nutzten

Ja genau so geht es mir Knoten im Kopf :confused:, trotz mehrmaligen durchlesens. Gibt es da nicht auf Dauer eine machbare und einfache Lösung? Ansonten wäre der Übergang keine Traits zu nutzten und die Methode einfach gleich in die Klasse zu schreiben? Ist zwar unschön und führt defintiv nicht zur Übersichtlichkeit aber wenigstens hat man dann keine Fehlermeldung oder?

Klar, das geht.

Nur lagere ich gerade alle meine Traits aus, und binde diese nur noch als Submodul ein.
Somit habe ich weniger Redundanzen und wenn ich etwas anpassen muss; dann nur an einer Stelle.
Das bereinigen kostet mich gerade so richtig Zeit.
Michael

Funktioniert dann aber nicht mit dem Module Store oder?

Kann man nicht mit Namespaces arbeiten oder geht das auch nicht und es kommt zur gleichen Fehlermeldung? Mit Namespaces und Klassen kome ich irgendwie zurecht aber nicht mit Traits.

Wenn ich versuche z.b. den Trait Bufferhelper in einen Namespace zu legen


namespace Fonzo\BufferHelper;

trait BufferHelper
{
    /**
     * Wert einer Eigenschaft aus den InstanceBuffer lesen.
     *
     * @param string $name Propertyname
     *
     * @return mixed Value of Name
     */
    public function __get($name)
    {
        /** @noinspection UnserializeExploitsInspection */
        return unserialize($this->GetBuffer($name));
    }/** @noinspection MagicMethodsValidityInspection */

    /**
     * Wert einer Eigenschaft in den InstanceBuffer schreiben.
     *
     * @param string $name Propertyname
     * @param mixed Value of Name
     */
    public function __set($name, $value)
    {
        $this->SetBuffer($name, serialize($value));
    }
}

dann bekomme ich die Meldung


$this->GetBuffer

Method GetBuffer not found in Bufferhelper

Wie muss das dann aussehen damit der Trait in einem Namespace funktioniert? Oder ist ein Namespace auch keine Lösung?

Irgendwann wird auch der Store Submodule unterstützen.
Traits sind eigentlich der einfachste Teil von Klassen, wenn man die ganzen Varianten von Vererbung betrachtet :smiley:
Und klar gehen Namespaces, das habe ich ja oben als Beispiel geschrieben.
Also für die Traits, nicht für die Klasse welche IPS benutzt um daraus Instanzen zu erschaffen.
Mein Namespace ist halt nicht fix in den Dateien der Traits, sondern wird über eval dynamisch passend zur Library geladen.

Wie hast du den Trait eingebunden? Das use Statement schaut wie aus?
Das müsste dann so aussehen:
use \Fonzo\BufferHelper\BufferHelper;
Michael


require_once(__DIR__ . "/../bootstrap.php");

use Fonzo\BufferHelper\BufferHelper;

bootstrap


/**
 * Loads the additional classes.
 */

// Load the additional classes
require_once(__DIR__ .DIRECTORY_SEPARATOR.'libs'.DIRECTORY_SEPARATOR.'bootstrap.php');

libs bootstrap


// Initialize the auto loader
@require_once(__DIR__ . '/Fonzo/AutoLoader.php');
\Fonzo\AutoLoader::Register(__DIR__);

autoloader


namespace Fonzo;


/**
 * A PHP PSR-0 Autoloader Class.
 * @link http://www.php-fig.org/psr/psr-0/
 */
class AutoLoader
{

    /**
     * @var array Base directories to be searched for classes.
     * @see AutoLoader::AddBaseDir()
     */
    protected static $baseDirs;

    /**
     * Registers the PHP PSR-0 autoloader and adds the specified base directory to the search list.
     * @param string $baseDir Absolute path to the base directory to be added to the search list.
     * @see AutoLoader::$baseDirs
     */
    public static function Register($baseDir)
    {
        // Remember the given base directory
        self::AddBaseDir($baseDir);

        // Register the PHP SPL Autoloader
        spl_autoload_register(__NAMESPACE__ . '\AutoLoader::load');
    }

    /**
     * Adds a base directory to the search list.
     * @param string $baseDir Absolute path to the base directory to be added to the search list.
     */
    public static function AddBaseDir($baseDir)
    {
        // Add the base directory
        self::$baseDirs[] = $baseDir;
    }

    /**
     * Iterates through the search list and tries to load the class file until the class was found.
     * This method is registered as PHP autoload method and automatically called by the interpreter.
     * @param string $className FQCN of the class to be loaded.
     * @return bool True if the class was found and false if not.
     */
    public static function Load($className)
    {
        // Assume the loader did not find the class
        $success = false;

        // Loop through all base directories
        foreach (self::$baseDirs as $baseDir) {
            // Try to load the class from the directory structure
            $success = self::LoadFromPath($baseDir, $className);
            // Break if the class was found
            if ($success) break;
        }

        // Return the result
        return $success;
    }

    /**
     * Tries to include the class file in the given base directory using the PSR-0 naming conventions.
     * @param string $baseDir Absolute path to the base directory to be added to the search list.
     * @param string $className FQCN of the class to be loaded.
     * @return bool True if the class exists after including the file or false if the file was not found or did not contain the class.
     */
    protected static function LoadFromPath($baseDir, $className)
    {
        // Generate the file name according to the PSR-0 specification
        $fileName = $baseDir . DIRECTORY_SEPARATOR . str_replace('\\', DIRECTORY_SEPARATOR, $className) . '.php';

        // Return false if the file doesn't exist
        if (! file_exists($fileName)) {
            return false;
        }

        // Require the file
        /** @noinspection PhpIncludeInspection */
        @require_once($fileName);

        // Check whether the class now exists and return the result
        return class_exists($className);
    }

}

Der Trait wird auch über use gefunden, das Problem ist das der Trait den parent nicht findet.

Den Luxus eines Autoloader habe ich mir erspart.
Zumal du damit dann wieder das gleiche ursprüngliche Problem hast.
In verschiedenen Dateien wird die gleiche Klasse erzeugt und es hagelt Fehlermeldungen.
Michael

Hm, das ist doch alles ein sehr unbefriedigend, es sollte doch eine einfache Möglichkeit geben Code in IP-Symcon wieder zu verwerten, das geht in anderen Sprachen bzw. Frameworks ja auch.

Eine endgültige funktionierende universelle Lösungen haben wir jetzt noch nicht oder um die Fehlermeldung zu vermeiden und das es immer funktioniert?

Klar haben wir die.
Entweder keine gleichen Namen bei Klassen und Traits nutzen (bisher ist das nur bei Traits aufgefallen, weil jeder die Namen mit kopiert hat :wink: ).
Oder halt die Traits mit Namespace versehen, welcher pro Library eindeutig sein muss.
Dein loader geht halt auch nur dann, wenn du jedesmal diesen einem anderen Namespace verpasst.
Warum dein loader und dein Trait jetzt nicht funktionieren…keine Ahnung, habe mir das nie im Detail angesehen.
Vermutlich weil der nur Klassen beherrscht und keine Traits (class_exists($className)).
Michael

Wahrscheinlich ist das vorübergehend die beste Lösung die Namen eindeutig zu benennen bis einem etwas Besseres eingefallen ist.

Was ich mir aber langfristig wünschen würde das z.B. IP-Symcon selber Standard Traits zur Verfügung stellt, die man einfach in jedem PHP Modul einbinden kann. So ähnlich ist das ja auch mit spezifische Methoden die IP-Symcon zur Verfügung stellt, nur das es dann eben auch für Standard Prozesse wie z.B. verschicken mit Curl, Variablenprofil anlegen, Bild in Media Objekt speichern usw. jeweils einfach ein Trait angeboten wird, den man in jedem PHP Modul verwenden kann. Es muss ja nicht immer jeder mit der gleichen Fragestellung von vorne anfangen oder Code umschreiben. Praktisch das was ein richtges PHP Framework ja auch macht nur eher mit Bezug auf Aufgabenstellungen von IP-Symcon.

Passiert ja auch. Wie jetzt mit HasActiveParent.
Wobei wir ja auf fertige Methoden für Profile schon länger warten :rolleyes:

Aber es wird immer Funktionen geben welche zwar irgendwo speziell sind, aber gelegentlich wiederverwendet werden.

Vielleicht löst sich das Thema auch mit dem geplanten Sandboxing irgendwann in Luft auf.
Michael

Ich versuche das gerade umzusetzen, bekomme aber immer eine Fehlermeldung:


class DebugClass
{

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

    public function DoIt()
    {
        $this->sendDebug('message', 'data', KL_DEBUG);
    }
}


// in der aufrufenden Klasse steht:

$MyObject = new DebugClass(
    function($Message, $Data, $Format) {
        $this->SendDebug($Message, $Data, $Format);
    }
);
$MyObject->DoIt();

liefert die Fehlermeldung

Abort Processing during Fatal-Error: Uncaught Error: Call to undefined method DebugClass::sendDebug() in C:\IP-Symcon\modules\iCal-Calendar\iCalCalendarReader\module.php:28
Stack trace:
#0 C:\IP-Symcon\modules\iCal-Calendar\iCalCalendarReader\module.php(772): DebugClass->DoIt()

Ich finde meinen Fehler einfach nicht :(. Irgendetwas scheint noch zu fehlen. Kann mir da jemand helfen?

Ist $this auch ein IPSModule? Denn sonst hat es ja die Funktion SendDebug nicht.

ja, ist es.

Aber ich habe es herausgefunden. Es muss

        call_user_func($this->sendDebug, 'message', 'data', 0);

heißen. Dann geht es.

Das Konstrukt sollte so nicht notwendig sein, ich benutze es auch in meinen Modulen nicht. Was eventuell noch fehlt ist das Initialisieren von sendDebug auf Klassenebene, also z.B.


class DebugClass
{
    private $sendDebug = null; // <--- Neu

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

    public function DoIt()
    {
        $this->sendDebug('message', 'data', KL_DEBUG);
    }
}

Das würde auch zur Fehlermeldung passen.

Nein, daran liegt es nicht.

Auch ein

echo (int) is_callable($this->sendDebug);

liefert eine 1

Also kann es eigentlich nur an der Art des Aufrufs liegen.

Seltsam, dass es bei dir auf diese Art geht und bei mir nicht.

Komisch, schau dir aber sonst gerne an, wie ich das beim GoogleAssistant und Alexa umgesetzt habe. Du findest die Einbindung in module.php und registry.php in beiden Modulen.