Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for PHP 8.4 #228

Closed
srjlewis opened this issue Oct 3, 2024 · 23 comments
Closed

Support for PHP 8.4 #228

srjlewis opened this issue Oct 3, 2024 · 23 comments

Comments

@srjlewis
Copy link
Contributor

srjlewis commented Oct 3, 2024

Hi

I am doing some eairly testing with PHP 8.4

I have found a conflict within the library

Fatal error: Cannot make static method PDO::connect() non static in class Aura\Sql\AbstractExtendedPdo in /some-project-dir/vendor/aura/sql/src/AbstractExtendedPdo.php on line 161

It is a result of a accepted PHP RFC https://wiki.php.net/rfc/pdo_driver_specific_subclasses which introduces a static connect method PDO::connect() as shown in the above method.

Here is lavavel's fix within there library https://github.com/laravel/framework/pull/52538/files

It looks like ExtendedPdoInterface::connect() would need renaming to somthing along the lines of ExtendedPdoInterface::autoConnect() and throughout the rest of the library.

I would then think ExtendedPdo:autoConnect() would looke somthing like.

class ExtendedPdo extends AbstractExtendedPdo
{
    public function autoConnect(): void
    {
        if ($this->pdo) {
            return;
        }

        // connect
        $this->profiler->start(__FUNCTION__);
        list($dsn, $username, $password, $options, $queries) = $this->args;
        if(version_compare(phpversion(), '8.4.0', '<')) {
            $this->pdo = new PDO($dsn, $username, $password, $options);
        } else {
             $this->pdo = PDO::connect($dsn, $username, $password, $options);
        }
        $this->profiler->finish();

        // connection-time queries
        foreach ($queries as $query) {
            $this->exec($query);
        }
    }
}

This would need to be a new majer version due to the big BC break ExtendedPdoInterface::connect() being public.

I can create a MR for this if needed.

@koriym
Copy link
Member

koriym commented Oct 4, 2024

It seems reasonable and appropriate to me. cc/ @pmjones @harikt @frederikbosch

@harikt
Copy link
Member

harikt commented Oct 4, 2024

Boooom.. @srjlewis Thank you for bringing this up and also nice pointers. We can make this next major version, but I am not sure what should we call this. I don't like the name autoConnect because it is not connecting automatically. Also this is a manual call. Any other alternatives you have in mind ?

Some of the methods came to my mind are createConnection, makeConnection, connectToDb.

@harikt
Copy link
Member

harikt commented Oct 4, 2024

PR #229

@srjlewis
Copy link
Contributor Author

srjlewis commented Oct 4, 2024

@harikt I do agree with the naming, I used autoConnect as an example, and can easily be changed, apart from this issue I have not run into any other issues with PHP 8.4

@frederikbosch
Copy link
Contributor

With driver specific subclasses in PHP, I think we should re-evaluate more than just the new PDO::connect method. Driver-specific classes are available in this library since #138 was merged. To what extend is that superseded in PHP 8.4? Should we not drop that if it is included in PHP itself?

If so, would it then not be better to drop < 8.4 for a new version 6.0? And just use override the connect method in order to support lazy connections? And, then maybe use an option for direct connections?

<?php

class ExtendedPdo
{
    public const CONNECT_IMMEDIATELY = 'immediate';

    protected array $args = [];
    protected bool $driverSpecific = false;

    public function __construct(
        string $dsn,
        ?string $username = null,
        ?string $password = null,
        array $options = [],
        array $queries = [],
        ?ProfilerInterface $profiler = null
    ) {
      // if no error mode is specified, use exceptions
        if (! isset($options[PDO::ATTR_ERRMODE])) {
            $options[PDO::ATTR_ERRMODE] = PDO::ERRMODE_EXCEPTION;
        }

        // retain the arguments for later
        $this->args = [
            $dsn,
            $username,
            $password,
            $options,
            $queries
        ];

        if ($options[self::CONNECT_IMMEDIATELY]) {
             $this->establishConnection();
        }

        // keep the rest of the constructor
    }

    #[\Override]
    public static function connect(string $dsn, string $username = null, string $password = null, array $options = null) {
    {
          $pdo = new self($dsn, $username, $password, $options);
          $pdo->driverSpecific = true;
          return $pdo;
    }

    // call this method from query, perform, execute etc
    private function establishConnection(): void
    {
       if ($this->pdo) {
            return;
       }

       if ($this->driverSpecific) {
            $this->pdo = PDO::connect($dsn, $username, $password, $options);$password, $options);
        } else {
            $this->pdo = new PDO($dsn, $username, 
        }
    }
}

@srjlewis
Copy link
Contributor Author

srjlewis commented Oct 4, 2024

@frederikbosch we could approch the issue has you mention, but I see a few issues in your approach.

  1. it would make the libaray PHP 8.4 only, I was trying to keep compatability with prior versions of php
  2. You have removed the compatability of initilizing the object with a profiler in the connect method

but by all means keep the ideas flowing

@frederikbosch
Copy link
Contributor

frederikbosch commented Oct 4, 2024

  1. Why keep the compatibility if you go to a version 6? People can use v5 for compatibility?
  2. That's because it's an example, not a PR. I would leave that in for sure.

@srjlewis
Copy link
Contributor Author

srjlewis commented Oct 4, 2024

It will help with a smooth migration/update path

We can release v6.0 and users can implement it before the release of PHP 8.4

This would also allow users to run PHP 8.x in production and do testing with PHP 8.4 before its release.

This is what I am doing at the moment, yes I know users can use some composer magic but that makes it more complicated for the users.

I also think it is a good idea to keep compatability with all supported version of PHP and not make users switch between versions of the libaray.

@frederikbosch
Copy link
Contributor

I disagree with that.

  1. Why rush to release before 8.4?
  2. There is no composer magic needed: if your are on PHP < 8.3, you use version 5 of AuraSQL, if you are going to use PHP 8.4, you use version 6 of AuraSQL. I don't see problem with that. That's no magic, that's how version management works.

Moreover, that is why there is semantic versioning: it's a contract how to deal with backward compatibility. When, you change the major version, you are going to break things. Now, with PHP 8.4 compatibility will be broken anyhow since the new connect method will force us to break things. You can better re-evaluate, and put the library in a mode that is going to proof itself again in the future. Hence, I suggest we slow down, and evaluate whether we need the driver specific parsers included in this library now PHP provides them in the core of PDO. And then see what is the best syntactic solution for immediate or manual connections.

@srjlewis
Copy link
Contributor Author

srjlewis commented Nov 11, 2024

Hi

Could we move forward with any ideas for the support for PHP 8.4 as there is now only 10 days to the GA release of PHP 8.4

I dont mind if you want to implement the 8.4 support in a different way, I just think time is catching up quickly.

@koriym
Copy link
Member

koriym commented Nov 15, 2024

Hi

Thank you all for your insightful discussions. I can see valid points in both approaches.

The clean v6 design proposed by @frederikbosch is ideal for applications that depend on a single PHP version. However, when libraries need to support both PHP 8.3 and PHP 8.4, some abstraction is necessary. In such cases, I believe implementing this abstraction at Aura.Sql's layer would be more appropriate than pushing it up to higher layers.

May I suggest the following approach:

For v5: Introduce a new internal method establishConnection() that handles version-specific PDO instantiation while keeping the existing connect() method for backward compatibility.

For v6: Since we can break BC, we can simply use the native PDO implementation targeting PHP 8.4+ only, without any abstraction.

I chose the name establishConnection as it clearly represents the intent and is a commonly used term in database contexts.

@frederikbosch
Copy link
Contributor

@koriym I don´t get your suggested approach completely. Could you elaborate what you want to do in v5? What do we gain with this new establishConnection() method?

As stated before, I am all for targeting 8.4 only for v6. It is not us that is breaking BC, it is PHP that is doing that (and rightfully so). Do I understand correctly that is what you are suggesting?

@koriym
Copy link
Member

koriym commented Nov 15, 2024

v5:

    /** This method is added, and nothing else changes. */
    public function establishConnection(): void
    {
        if ($this->pdo) {
            return;
        }

        // connect
        $this->profiler->start(__FUNCTION__);
        list($dsn, $username, $password, $options, $queries) = $this->args;
        if(version_compare(phpversion(), '8.4.0', '<')) {
             $this->pdo = new PDO($dsn, $username, $password, $options);
        } else {
             $this->pdo = PDO::connect($dsn, $username, $password, $options);
        }
        $this->profiler->finish();

        // connection-time queries
        foreach ($queries as $query) {
            $this->exec($query);
        }
    }

What we can gain from this method:

Libraries that must support both PHP 8.3 and PHP 8.4 can be made compatible with both PHP versions by modifying them to call this method.

v6:

targeting 8.4 only for v6

Yes.

Hope this makes things clear.

@srjlewis
Copy link
Contributor Author

srjlewis commented Nov 15, 2024

I dont think it is worth changing v5, as the connect() signature is totally different

v5

public function connect(): void

v6 and pdo in php 8.4 onwards

public static function connect(string $dsn [, string $username [, string $password [, array $options ]]])

so just including establishConnection() would not work and would not benfit v5 and v5 cant even run on PHP 8.4 with it's current connect() signature.

What I was trying to do in version v6 was change the connect() method to match PDO's new signuture and logic, move the connect() logic to establishConnection() method, whist making v6 compatable with all supported versions of PHP.

So all version of PHP would be able to use v6 and PHP <= 8.3 would be able to use the new PDO connect syntax due to the changed connect() method

    public static function connect(
        string $dsn,
        ?string $username = null,
        ?string $password = null,
        ?array $options = [],
        array $queries = [],
        ?ProfilerInterface $profiler = null
    ): static {
        $pdo = new static($dsn, $username, $password, $options ?? [], $queries, $profiler);
        $pdo->establishConnection();
        return $pdo;
    }

I dont mind making v6 compatable with PHP 8.4 above I would only need to change establishConnection() to

    public function establishConnection(): void
    {
        if ($this->pdo) {
            return;
        }

        // connect
        $this->profiler->start(__FUNCTION__);
        list($dsn, $username, $password, $options, $queries) = $this->args;
        $this->pdo = PDO::connect($dsn, $username, $password, $options);
        $this->profiler->finish();

        // connection-time queries
        foreach ($queries as $query) {
            $this->exec($query);
        }
    }

I have updated the git actions to include PHP 8.4 in testing and all versions of PHP pass

@frederikbosch
Copy link
Contributor

I would do the latter and on-top I really believe we need to investigate how our parsers. What use do they still have?

@frederikbosch
Copy link
Contributor

Look at this commit in php-src, that is pretty much what we are offering with our parsers.

@frederikbosch
Copy link
Contributor

Why don't we merge the proposed code (after review) of @srjlewis, tag v6 beta 1, let people use that if they want to use PHP 8.4 from today? Investigate the parsers, change the code where necessary and then move towards v6-rc.1 and finally v6.0?

@srjlewis
Copy link
Contributor Author

@frederikbosch I do aggree they need looking at, I was/am aming for compatability first of all and as we move forward, and the userbase move to newer versions of PHP I totally agree, with reviewing and removing the parsers.

@srjlewis
Copy link
Contributor Author

@frederikbosch I have done the update requested, and added a test for the connect() method and update composer

@koriym
Copy link
Member

koriym commented Nov 15, 2024

I apologize for my earlier confusion. You are right - this is about the method name conflict between Aura.Sql's connect() and PHP 8.4's PDO::connect(). That's why we need v6 for PHP 8.4 support.

Thank you for the clarification.

@srjlewis
Copy link
Contributor Author

srjlewis commented Nov 15, 2024

@frederikbosch @harikt

I was thinking of @harikt point of putting a establishConnection() method into v5, but as a alias of the connect() like

public function establishConnection(): void
{
     $this->connect();
}

This would allow users to switch to the establishConnection() mthod and be able to use the same api on PHP <=8.3 or >=8.4, they would only need to change calls from connect() to establishConnection() in there code

@harikt
Copy link
Member

harikt commented Nov 16, 2024

@srjlewis We can add a method as you suggested and promote it in 5x, so people using older versions can use it. That is just a ux I believe, so easier to switch from 5.x to 6.x.

@harikt
Copy link
Member

harikt commented Nov 16, 2024

I have merged #229 to 6.x .

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants