Close a connection - __destruct usage possible?

Hello all,

a) I have this class that connects to something.
b) Then I have some abstract class that does abstract things and extends the connection class.
c) Then I have another class that extends those abstract things and talks with a controller, and, finally,
d)I have that controller class that talks with the form and with the class that extends the abstract.

This is more or less the structure I’m in.

The connection class connects, and it does that really nice. No issues there. However, I would like your help in order to found out a way to, implement, on this structure, a logout and disconnect functionality.

I need to call the logout, explicitly (?)
Because I should made a logout only once, but only after all the instructions are processed. So, at the end only. But this at the end seems quite hard to find. If we have 1 method to call, it will be at the end of that method. If we have 2 it will be at the end of those 2… etc… So, I presume only explicitly calling a logout will do it.

HOWEVER, where should we call it? I presume we shouldn’t call it on the “php that is next to the FORM” (the “view”) because we are far away from the connection layer… however, it seems to be the perfect spot to do that, because it will be there, were we will know when should the logout be called.

Can I have your help please?

Thanks a lot,
Márcio

You know when you code your class that you’re going to throw an exception, why would you catch it and not deal with it? Because it’s upto the consuming object/client to decide how to proceed.

Exceptions are for client code, not your own internals.


try{
  $socket = new Socket('ssl://eppserver.pt', 3821);
}catch(SocketException $e){
  printf(
    'Socket Error (%d): %s',
    $exception->getCode(),
    $exception->getMessage()
  );
  exit;
}


<?php
class Socket
{
  protected
    $_pointer = null;
    
  
  public function __construct($host, $port, $timeout = 5){
    $errnum = 0;
    $errstr = '';
    $this->_pointer = fsockopen($host, $port, $errnum, $errstr, $timeout);
    if(false === is_resource($this->_pointer)){
      throw new SocketException($errstr, $errnum);
    }
  }
  
  public function write($data, $length = null){
    $data   = (string)$data;
    $length = null === $length ? strlen($data) : (int)$length ;
    return fwrite($this->_pointer, $data, $length);
  }
  
}

Should I throw and catch later? Shouldn’t I throw at all?

My goal was to try to read or try to write, if it doesn’t work for some reason, throw an exception.

Is it like this? How can we deal with the errors then?

class ConexaoSocket
{

    private $_host;
    private $_porto;
    private $_filePointer;


    public function __construct()
    {

        $this->_host = 'ssl://eppserver.pt';
        $this->_porto = 3821;
        
        $this->_filePointer = fsockopen($this->_host, $this->_porto);
 
        return $this->_filePointer;
     }


 
    public function escrever($dados)
    {

       $bytesEscritos = fwrite($this->_filePointer, $dados);

        return;
    }


    public function ler($length)
    {
   
        $bytesLidos = fread($this->_filePointer, $length);
        return;
    }

    public function __destruct()
    {
        fclose($this->_filePointer);
    }
} 


And worst of all it is that I see that using the connection to do the fwrite and fread etc… was already suggested and I was unable to connect the dots back there.

:s

If I can make that change, I will. If not, maybe I can pass this login and logout to my controller class. (: ?

I will try again.

K. Regards,
Márcio

Because it is abstract. The whole point of declaring a class to be abstract is to prevent direct instantiation and force the creation of at least one child class.

Example I’ve used. I have a database driver class that sets the mold for database connectivity. It’s abstract though because in a child class I set the particulars of the database being driven - MySQL, MsSQL, Postgre, etc.


abstract class Database {
// herein are the public methods for
// queries.  Several abstract methods
// are present though
}

class Mysql extends Database {
// herein the abstract methods are defined
// for the particulars of a MySQL connection
}

Abstract classes are one way to insure a class has certain characteristics. The other is Interfaces.

No. __destruct will be called when you unset the last reference to the object, not merely unset a reference to an object. These are often the same, many programmers don’t create more than one reference to the object. But many do - especially in frameworks that advice you use the factory pattern to make a copy of the object and give it to every class in the system in the name of having a “loosely coupled” system.

General Note: Objects in PHP are always references unless the clone statement is used explicitly.

So, some sample code to illustrate.


$a = new Foo();

$b = $a;

// That's the same as

$c &= $a

// Doesn't really matter because assignments of objects
// in PHP are always by reference! If we need a new
// totall independent object then we clone.

$d = clone($a);

// And here $d's magic __clone method will be invoked
// if it has one.

unset($d);

// Since $d was a clone its __destruct will now be
// invoked.

unset ($a);

// However the __destruct method will not be invoked
// here because references at $b and $c still exist.

unset ($c, $b);

// When the last reference dies the __destruct method
// gets called.

Sure.

Yes, and I don’t like using private, I think private provides very little benefits.

Preference, where possible I like to initialise vars.

Open/Closed Principle, I would have to alter the object if the server or port changed. Which is likely.

It allows me to pass the error message and code to the exception, otherwise I’d have to make something up, I have no imagination.

Yes.

I’d say so.

Allowing access to the error code and string if created is meaningless, if they happen to exist they’ll be in the guaranteed exception I’ll throw.

“your” headache? :shifty:

Anthony. :stuck_out_tongue:

It does. :slight_smile:

Get rid of the *Frame methods and create generic read/write/open/close ones.

Ok.
I can’t test it at the moment but here is the connection:


class ConexaoEppFccn
{
    private $_host;
    private $_porto;
    private $_filePointer;

    //private $_filePointer = false;

    public function __construct()
    {

        $this->_host = 'ssl://serverepp.pt';
        $this->_porto = 3821;

        try
        {
           
            $this->_filePointer = fsockopen($this->_host, $this->_porto);

            if ($this->_filePointer === FALSE)
            {
                throw new Exception('Não houve possibilidade de colocar o file pointer no socket dado.');
            }
            else
            {
                return $this->_filePointer;
            }

        }

        catch(Exception $e)
        {
            echo "Erro de Conexão: " .$e->getMessage();
        }

    }

    public function getFrame()
    {
        $binaryStringPackOfFirstFourBytes = fread($this->_filePointer, 4);

        $unpacked = unpack('Nlength', $binaryStringPackOfFirstFourBytes);

        $length = $unpacked['length'];

        $remainBinaryPack = fread($this->_filePointer, ($length - 4));

        $xml = new SimpleXMLElement($remainBinaryPack);

        return $xml;
    }

    public function readFrame()
    {
        $binaryStringPackOfFirstFourBytes = fread($this->_filePointer, 4);

        $unpacked = unpack('Nlength', $binaryStringPackOfFirstFourBytes);

        $length = $unpacked['length'];

        $remainBinaryPack = fread($this->_filePointer, ($length - 4));
    }

    public function enviarFrame($xml)
    {
        try
        {
            $bytesEscritos = fwrite($this->_filePointer, pack('N', (strlen($xml)+4)).$xml);

            if (empty($bytesEscritos))
            {
                throw new Exception('Erro ao tentar escrever.');
            }

        }
        catch(Exception $e)
        {
            echo "Erro no envio da Frame: " .$e->getMessage();
        }
    }

    public function __destruct()
    {
        fclose($this->_filePointer);
    }

}

Now, this needs to be more abstract right?

Nice then. :slight_smile:

It took me two months to almost understand how to build one, and now you telling me that (and you are not the only one :blush:) they are not a good idea. :goof:

I thought they were in a sense that I doesn’t waste resources by calling a connection again and again. I’ve actually see this, after a lot of var_dumps, and I notice that, the connection dump, despite the several sending frames, it only appears once and I thought: “nice, it seems to be working”.

Care to share some thoughts about it, or resources about why isn’t this a good option? Isn’t always like that yes? It must depend on the scenarios? I’ve brought this from a database connection class that I created some months ago.

And one last question as well. This same logic can be applied if we need to login and we need only one login yes?

Thanks a LOT for your time and precious guidance,
Márcio

Yes that looks good. From your initial posts I thought you had classes extending the connection, with separation it’s easy as the destructor will only ever get called once.

edit: Although singletons are not a good idea but that’s an entirely different topic.

Thank you very much for the clarifications.

I have found a way do deal with the logout and login that does not involve class restructure, however, this seems to be a very nice way of doing things, and really OO, I realise the metaphor of blueprint that I read over and over, and I still don’t do (like for example, when I have on my connection class the server address and the port for example, that’s a real case where I forgot the blueprint).

All this to say that, I will make this thing work, but I would like to further investigate over the code provided so, if you don’t mind, after work, I will keep on this quest of understanding the code previously provided.

I will however, create a new topic for it, because this is now nothing to do with close connection and destruct.

Thanks again,
Márcio

Yep.

As for interfaces and implementors, that’s a huge can of worms in and of itself.

Like so?


class ConexaoSocket
{
    private $_host;
    private $_porto;
    private $_filePointer;

    public function __construct()
    {

        $this->_host = 'ssl://eppserver.pt';
        $this->_porto = 3821;

        try
        {
            $this->_filePointer = fsockopen($this->_host, $this->_porto);

            if ($this->_filePointer === FALSE)
            {
                throw new Exception('Não houve possibilidade de colocar o file pointer no socket dado.');
            }
            else
            {
                return $this->_filePointer;
            }

        }

        catch(Exception $e)
        {
            echo "Erro de Conexão: " .$e->getMessage();
        }

    }
    
    public function escrever($dados)
    {
        
        try
        {
            $bytesEscritos = fwrite($this->_filePointer, $dados);

            if (empty($bytesEscritos))
            {
                throw new Exception('Erro ao tentar escrever.');
            }

        }
        catch(Exception $e)
        {
            echo "Erro de escrita: " .$e->getMessage();
        }
        
        return;
    }

    public function ler($length)
    {
        try
        {
            $bytesLidos = fread($this->_filePointer, $length);

            if (empty($bytesLidos))
            {
                throw new Exception('Erro ao tentar ler.');
            }

        }
        catch(Exception $e)
        {
            echo "Erro de leitura: " .$e->getMessage();
        }
        
        return;
    }

    public function __destruct()
    {
        fclose($this->_filePointer);
    }

}

If so, I will now need to use this read, write methods to read and write FRAMES ?

Ok. I will need to think about it more often. I’m only seeing on one direction. :s

The only class that is declared as child of this connection class is the abstract class. From this abstract class, we have a bunch of others that extend this abstract class. But the connection class is only extended by the abstract class.

I have one already but no destruct is present.

So, something like this perhaps:


/**
 * Description of ConexaoEppFccn - Classe Singleton para Conex&#227;o a EPP
 * @version 0.1
 */
class ConexaoEppFccn
{
    private $_host;
    private $_porto;

    private static $_instance = null;

    /**
     * @desc Conecta ao servidor EPP e, se com sucesso devolve uma resource.
     * @return <resource>
     */
    final public function __construct()
    {

        $this->_host = 'ssl://eppserver.pt';
        $this->_porto = 3881;
        
        //adicionado
        $this->_filePointer = false;

        try
        {
            //prepara o socket para ser lido como se fosse um ficheiro.
            $this->_filePointer = fsockopen($this->_host, $this->_porto);

            //AQUI &#233; do tipo stream;
            //var_dump($filePointer);

            if ($this->_filePointer === FALSE)
            {
                throw new Exception('N&#227;o houve possibilidade de colocar o file pointer no socket dado.');
            }
            else
            {
                return $this->_filePointer;
            }

        }

        catch(Exception $e)
        {
            echo "Erro de Conex&#227;o: " .$e->getMessage();
        }

    }

    public static function getInstance()
    {
        if (self::$_instance === null)
        {
            self::$_instance = new self;
        }

        return self::$_instance;
    }

    private function __clone()
    {
        //vazio de prop&#243;sito.
    }

    public function __destruct()
    {
        $resposta = array();

        //not sure what path should I put here. :s
        $xmlObj = simplexml_load_file('RepositorioXml/EppLogout.xml');

        $xmlObj->command->clTRID = uniqid('webhs-logout-');

        //prepara
        $xmlString = $xmlObj->asXML();

        //envia logout
        $this->enviarFrame($xmlString);

        $respostaLogoutXML = $this->getFrame();

        $response = $respostaLogoutXML->response->result[0];

        $codigoResposta = (int)$response["code"];

        $resposta["cd"] = $codigoResposta;

        $resposta["msg"] = $response->msg;

        fclose($this->_filePointer);

        return $resposta;
    }


}//fim da classe.

After this, each time a view calls an object and all the process runs, we will be sure that, at the end of that called script, this __destruct method (assuming it’s working) will be called and all will run smoothly as expected?? :D:D:D:D??? :shifty::shifty:

Márcio

I thought that the “throw” could only be used within a try catch.
Now it makes sense, we throw an exception when we believe it’s a good place for doing so, and, later on, we try to catch it, if it exists. And since we are doing on the client side of things, this can be displayed on a convenient manner with validations errors and so on…

yes?

You have done a lot. :stuck_out_tongue: As always.
Please I’m here. Newbie as ever. :s

protected
    $_pointer = null;

Protected so that descendants can access it.
Why? For a future proof?

Why = null;
Why not just $_pointer; ?

public function __construct($host, $port, $timeout = 5){

You have removed the private properties and instead, used constructor arguments.

Why?

You have added a few attributes:
Is it to make the exception catch more effective?

fsockopen($host, $port, $errnum, $errstr, $timeout);

Using length so that this could be used with other projects were we need to write after a given number?

public function write($data, $length = null)
is_resource

Proper then empty hm?

$length = null === $length ? strlen($data) : (int)$length ;

I will go for ternary were space and optimization could be my concerns.
For now, I must know how to read it. Only after I can read it fast, and better. :slight_smile:
I will revert to more lines if you don’t mind. (:

UPDATE:


public function __construct($host, $port, $timeout = 5){
    $errnum = 0;
    $errstr = '';

Why some options are on the __construct arguments, and others are inside ?

Thanks a lot,

Until my headache,
Márcio

Whoa, that looks messy.


class Connection
{
  /***
   *
   *read / write methods
   *
   **/
  
  public function __destruct(){
    fclose($this->_resource);
  }
}


class AuthenticatedConnection
{
  public function __construct(Connection $connection){
    
  }
  
  public function login(){
    
  }
  
  public function logout(){
    $this->connection->write('HOY SERVER: DO LOG ME OUT');
  }
  
  public function __destruct(){
    $this->logout();
  }
}


<?php
$connection = new Connection('host', 23);
$authenticatedConnection = new AuthenticatedConnection($connection, 'username', 'password');

$commandController = new CommandController();
$response = $commandController->execute($authenticatedConnection, new DomainRegistrationCommand('WhoIsYourDaddyAndWhatDoesHeDo.com'));
?>

$length = null === $length 

What does this mean?

Context:

$length = null === $length ? strlen($data) : (int)$length ;

if something $length = strlen($data) else (int)$length;

:sick:

Just search this forum for ‘singleton’. There’s been a lot of discussion on the topic. There’s a nice article here

edit: Sorry this was in reply to your last post.

I don’t understand your architecture. Please post the bare-bones class definitions containing the parts you’re having problems with. Though you cant ever initiate an abstract class. That’s the whole point. They are marked as abstract because the behaviour is incomplete.

I’m confused about what it is you’re trying to accomplish. After reading some of the posts in this thread, part of me wants to say don’t worry about it, PHP will clean up when the script finishes.

When you say “logout()” though, I start thinking about sessions, serialize()'d objects, session_set_save_handler along with it’s garbage collector argument, and having that gc function unserialize old session objects so their deconstructor can be used to “logout” before deleting them from the session storage medium. (file, memcachd, etc)