Ankündigung

Einklappen
Keine Ankündigung bisher.

[Erledigt] Class - Trigger bei Methodenaufruf

Einklappen

Neue Werbung 2019

Einklappen
X
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

  • [Erledigt] Class - Trigger bei Methodenaufruf

    Hi leute,
    such mich seit Stunden im Netz tot und hab nichts passendes gefunden. Daher stell ich meine Fragen mal direkt Euch.

    Was möchte ich machen?
    Ich habe eine Klasse mit einem Konstruktor und mehreren Methoden. Die Klasse und vorallem einzelne Methoden sollen nur genutzt werden können wenn bestimmte Parameter erfüllt sind.

    Möglichkeit 1:
    Der Klassen-Trigger "__call" hilft mir nicht weiter da dieser aufgerufen wird wenn eine Methode nicht vorhanden ist. Ich benötige das exakte Gegenteil dieses Triggers.
    Frage: Ist jemandem eine solche Funktion oder ein Workaround bekannt?

    Möglichkeit 2
    Im Konstruktor hab ich direkt meine Prüfung drin, sollte diese nicht stimmen so wird die Klasse direkt im Konstruktor wieder zerstört. Problem hierbei ist das meine Klasse trotzdem bestehen bleibt und meine Methode aufgerufen werden kann.
    Frage: Wie kann man eine Klasse komplett im Konstrukor bereits wieder zerstören?

    PHP-Code:
      $MYCHECK true;
      
      
    $TEST = new test();
      echo 
    $TEST->display();    // Wenn $MYCHECK==true dann sollte kein Inhalt zu sehen sein
      
      
    class test{
      
        public function 
    __construct(){
            GLOBAL 
    $MYCHECK;
            if(
    $MYCHECK){
                
    settype(&$this,'null');
                unset(
    $this);
            }
    //end of if
        
    }//end of method
        
        
    public function __destruct(){
            echo 
    "TEST DESTROYED";
        }
    //end of method
        
        
    public function display(){
            return 
    "Hallo Welt!";
        }
    //end of method
        
      
    }//end of class 
    Möglichkeit 3
    Ich baue einen "Tunnel" aus einer PHP Klasse und missbrauche die Funktion "__call". Ich besitze eine Dummyklasse in der lediglich der Konstruktor und die Call Methode deklariert sind. Alle Methodenaufrufe führe ich nun über diese Klasse aus, welche die Methoden ja nicht besitzt und somit die __call Funktion startet. Diese macht dann meine Prüfung der Parameter und lädt bei Erfolg die jeweilige Methode der jeweiligen Klasse. Die Tunnelklasse reicht sozusagen die Anfragen bei erfolgreicher Prüfung direkt zur Zielklasse durch.
    Frage: Macht diese Version sinn oder könnte das Missbrauchen des Errorhandlers eventuell bei sehr vielen Useranfragen das System beeinflussen?

    Danke im vorraus!

  • #2
    Zitat von Broady Beitrag anzeigen
    Frage: Wie kann man eine Klasse komplett im Konstrukor bereits wieder zerstören?
    Abgesehen davon, dass du wohl nicht die Klasse zerstören willst sondern das Objekt: gar nicht.

    Aber mach dich mal über die Factory Patterns schlau, das könnte dir helfen!

    Factory Method - php bar
    [IMG]https://g.twimg.com/twitter-bird-16x16.png[/IMG][URL="https://twitter.com/fschmengler"]@fschmengler[/URL] - [IMG]https://i.stack.imgur.com/qh235.png[/IMG][URL="https://stackoverflow.com/users/664108/fschmengler"]@fschmengler[/URL] - [IMG]http://i.imgur.com/ZEqflLv.png[/IMG] [URL="https://github.com/schmengler/"]@schmengler[/URL]
    [URL="http://www.schmengler-se.de/"]PHP Blog[/URL] - [URL="http://www.schmengler-se.de/magento-entwicklung/"]Magento Entwicklung[/URL] - [URL="http://www.css3d.net/"]CSS Ribbon Generator[/URL]

    Kommentar


    • #3
      Zitat von Broady Beitrag anzeigen
      Möglichkeit 1:
      Der Klassen-Trigger "__call" hilft mir nicht weiter da dieser aufgerufen wird wenn eine Methode nicht vorhanden ist. Ich benötige das exakte Gegenteil dieses Triggers.
      Frage: Ist jemandem eine solche Funktion oder ein Workaround bekannt?
      Ich habe mich für diesen Weg entschieden um "Trigger" zu realisieren.

      Du benennst die Methode die einen Triggereffekt hat t_methodname. dadurch wird beim Aufruf von $obj->methodname __call ausgeführt. Nun kannst du die Methode t_methodname per call_user_func_array() ausführen oder ggf. eine Exception werfen wenn es die Methode nicht gibt.

      Hat unter anderem den Vorteil das man noch entscheiden kann welche Methode Trigger enthält und welche nicht.
      "Alles im Universum funktioniert, wenn du nur weißt wie du es anwenden musst".

      Kommentar


      • #4
        @fab: Ok hab ich mir angesehen, dass würde gehen und entspräche "Möglichkeit 3" dem Klassen-Tunnel. Der Code sieht wie folgt aus und funktioniert soweit:

        PHP-Code:
            $ACCESS_GRANTED true;

            class 
        tunnel{
                
                static public function 
        factory($className$params null){
                    GLOBAL 
        $ACCESS_GRANTED;
                    
                    if(!
        is_string($className) OR !strlen($className)){
                        echo 
        'Die zu ladende Klasse muss in einer Zeichenkette benannt werden!';
                    }elseif(!
        $ACCESS_GRANTED){
                        echo 
        'Access denied: Parameter wurden nicht erfüllt!';
                        return new 
        tunnel();    // Tunnel Instanz erzeugen um PHP Fehler zur unterdrücken das die Methode nicht vorhanden ist!
                    
        }else{
                        return new 
        $className($params);
                    }
        //end of if
                    
                
        }//end of method
                
                
                
        public function __call($name,$arguments){
                    
        // Unterdrücken vom PHP Fehler
                
        }//end of method
                
            
        }//end of class
            
            
            
        class test{
            
                public function 
        __construct(){  }//end of method
                
                
        public function display(){
                    return 
        "Hallo Welt!";
                }
        //end of method
            
            
        }//end of class
            
            
            
        $TEST tunnel::factory('test');
            
            echo 
        $TEST->display(); 
        Das sichert mir zwar nicht jede Methode einzeln ab aber hilft mir schon einmal ungemein weiter. Nur zur Info: Gibts da echt keine Funktion oder Workaround zu Version 1?

        Kommentar


        • #5
          @Dark Guardian: Hmm das geht natürlich auch, aber die Frage ist halt inwiefern das "gut" ist wenn man ständig den Error-Handler ausnutzt. Immerhin isser dafür ja nicht gedacht. Gibt's da Benchmarks ob das System dadurch beeinflusst wird? Immerhin sind es in PHP paar Schritte mehr die der Code machen muss.

          Kommentar


          • #6
            Hallo,

            dein "Tunnelobjekt" heißt wird ich das richtig erfasse Proxypattern oder Stellvertreter-Entwurfsmuster.

            Grundsätzlich ist dein Ansatz mit GLOBAL auch nicht wünschenswert.

            PHP-Code:
            <?php
            class AccessProxy {
              protected 
            $_access;
              protected 
            $_className;
              protected 
            $_params;  

              protected 
            $_instance;

              public function 
            __construct($access$class$params = array())
              {
                
            $this->_access $access;
             
                if (
            is_object($class)) {
                  
            $this->_instance $class;
                } else {
                  
            $this->_className $className;
                  
            $this->_params $params;
                }
              }

              public function 
            getInstance()
              {
                if (
            $this->_instance === null) {
                  
            $reflection = new ReflectionClass($this->_className);
                  
            $this->_instance $reflection->newInstanceArgs($this->_params);
                }
                return 
            $this->_instance;
              }

              public function 
            __call($method, array $params)
              {
                
            $callback = array($this->getInstance(), $method);
                if (!
            is_callable($callbackfalse)) {
                  throw new 
            BadMethodCallException("invalid method called: " $method);
                }
                if (!
            $this->_access) {
                  throw new 
            RuntimeException("access denied");
                }
                return 
            call_user_func_array($callback$params);
              }
            }

            // example
            class Person
            {
              protected 
            $_firstname;
              protected 
            $_lastname;
             
              public function 
            __construct($firstname$lastname)
              {
                
            $this->_firstname $firstname;
                
            $this->_lastname $lastname;
              }
              public function 
            getName()
              {
                return 
            $this->_firstname " " $this->_lastname;
              }
            }

            // test

            $access false;
            $proxy = new AccessProxy($access"Person", array("Peter""Meier"));
            echo 
            $proxy->getName(); // exception: access denied

            $access true;
            $proxy = new AccessProxy($access$proxy->getInstance());
            echo 
            $proxy->getName(); // Peter Meier
            "[URL="http://www.youtube.com/watch?v=yMAa_t9k2VA&feature=youtu.be&t=25s"]Mein Name ist Lohse, ich kaufe hier ein.[/URL]"

            Kommentar


            • #7
              Zitat von Broady Beitrag anzeigen
              @fab: Ok hab ich mir angesehen, dass würde gehen und entspräche "Möglichkeit 3" dem Klassen-Tunnel. Der Code sieht wie folgt aus und funktioniert soweit:

              PHP-Code:
              ... 
              Das sichert mir zwar nicht jede Methode einzeln ab aber hilft mir schon einmal ungemein weiter. Nur zur Info: Gibts da echt keine Funktion oder Workaround zu Version 1?
              brr, unschön. Ich kenne deinen genauen Anwendungsfall nicht aber das ist irgendwie von hinten durch die Brust ins Auge. Vielleicht ist eine Wrapper-Klasse eher etwas für dich, die den Zugriff auf das enthaltene Objekt regeln?

              Edit: Das Beispiel von Chriz geht dazu wunderbar, du brauchst vermutlich nur noch einen Setter für $access
              [IMG]https://g.twimg.com/twitter-bird-16x16.png[/IMG][URL="https://twitter.com/fschmengler"]@fschmengler[/URL] - [IMG]https://i.stack.imgur.com/qh235.png[/IMG][URL="https://stackoverflow.com/users/664108/fschmengler"]@fschmengler[/URL] - [IMG]http://i.imgur.com/ZEqflLv.png[/IMG] [URL="https://github.com/schmengler/"]@schmengler[/URL]
              [URL="http://www.schmengler-se.de/"]PHP Blog[/URL] - [URL="http://www.schmengler-se.de/magento-entwicklung/"]Magento Entwicklung[/URL] - [URL="http://www.css3d.net/"]CSS Ribbon Generator[/URL]

              Kommentar


              • #8
                -----

                Das Anwendungsbeispiel ist wie folgt:
                Ich habe einen Quellcode der durch ein Lizenzsystem gesichert werden soll. Der Kerncode ist durch Zend etc. verschlüsselt, so auch die Klasse zum prüfen der Lizenz und alle weiteren Klassen. Der restliche Code ist ungeschützt und das Lizenzsystem könnte somit umgangen werden.

                Bei jeder Instanz einer Klasse muss nun im Code geprüft werden ob der Lizenzcode gültig ist. Da ich vermeiden will einen Prüf-Codeblock bei der Entwicklung in jede Klasse zu bauen, muss dieser Check teilweise automatisch erfolgen.

                Ziel ist es den Lizenzcheck ohne größeren Aufwand bei der weiterer Entwicklung des Projektes mit der Klasse zu verbinden. Das Lizenzsystem soll weitgehend automatisch die Klassen schützen indem alle Klassen durch einen Tunnel müssen. Bevor die Klasse also instanziert wird muss sie durch den "Lizenzcheck".

                -----

                Ich hoffe ich konnte das irgendwie verständlich erklären. Ich weis der Code ist durch Zend eh gesichert, aber das schützt trotzdem nicht komplett.

                @fab: Inwiefern ist das "unschön"?
                @chriz: Das mit der global variable diente nur zu Testzwecken. Sinn ist es die komplette Klasse zu schützen. Aber ich teste das mit deinem Beispiel nochmal, danke.

                Kommentar


                • #9
                  Zitat von Broady Beitrag anzeigen
                  @fab: Inwiefern ist das "unschön"?
                  Erstmal natürlich $_GLOBALS aber das hat sich ja erledigt. Dann widerspricht es dem Separation of Concerns Prinzip, deine tunnel-Klasse ist gleichzeitig Factory und Dummy. Die Dummy-Objekte an sich "um Fehler zu unterdrücken" sind in den seltensten Fällen sinnvoll. Wenn der Code nicht ausgeführt werden darf, brich ihn ab anstatt ihn mit falschen Objekten zu füttern.

                  Und da sind wir auch bei dem Punkt wo dein Design von vorneherein fehlerhaft ist, du willst den gesamten Code schützen, dann überprüfe die Lizenz einmal am Anfang und nicht 1000 mal mittendrin, das ist 1. unperformant und 2. sinnlos. Oder ich verstehe deine Anforderung nicht
                  [IMG]https://g.twimg.com/twitter-bird-16x16.png[/IMG][URL="https://twitter.com/fschmengler"]@fschmengler[/URL] - [IMG]https://i.stack.imgur.com/qh235.png[/IMG][URL="https://stackoverflow.com/users/664108/fschmengler"]@fschmengler[/URL] - [IMG]http://i.imgur.com/ZEqflLv.png[/IMG] [URL="https://github.com/schmengler/"]@schmengler[/URL]
                  [URL="http://www.schmengler-se.de/"]PHP Blog[/URL] - [URL="http://www.schmengler-se.de/magento-entwicklung/"]Magento Entwicklung[/URL] - [URL="http://www.css3d.net/"]CSS Ribbon Generator[/URL]

                  Kommentar


                  • #10
                    Der Code darf im Falle eines "access denied" nicht abgebrochen werden. Die Software soll automatisch in eine Trialmodus versetzt werden und nicht abbrechen. Sobald bei irgendeinem Lizenzcheck ein Fehler auftritt, soll der Trialstatus ausgeführt werden. Ich will folgendes verhindern:

                    Bei nur einem Aufruf am Anfang:
                    Code:
                    - Lizenzklasse wird instanziert
                    - Check Lizenz failed -> $access = false
                    
                    - fremder Programmierer arbeitet Code ein und setzt $access = true. (Auf welchem Weg auch immer)
                    
                    - "myclass" wird instanziert
                    - $access = true ? Dann GO!
                    - Funktion wird ausgeführt
                    Beim Check in jeder Instanz:
                    Code:
                    - Lizenzklasse wird instanziert
                    
                    - fremder Programmierer arbeitet Code ein und setzt $access = true (Auf welchem Weg auch immer)
                    
                    - "myclass" wird instanziert
                    - Check Lizenz failed -> $access = false
                    - $access = false ? Kein Zugriff auf Klasse!
                    - System wird in Trialstatus versetzt
                    Sobald eine geschützte Datei (z.B. Lizenz-Klasse) auch nur Ansatzweise geändert wird, so merkt das System das und sperrt die Webseite umgehend da diese Prüfung ein bestandteil des Lizenzsystems ist. Schwierig zu erklären. Das ganze wird auch nicht 1000 mal geprüft, wenn es hochkommt 5 - 10 mal nur.

                    Kommentar

                    Lädt...
                    X