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

Remove "final" from methods in Table schema class #6573

Open
aimeos opened this issue Oct 25, 2024 · 13 comments
Open

Remove "final" from methods in Table schema class #6573

aimeos opened this issue Oct 25, 2024 · 13 comments

Comments

@aimeos
Copy link
Contributor

aimeos commented Oct 25, 2024

Feature Request

What

There are only two methods in the Table schema class which are marked as final, which seems to make no sense:

dbal/src/Schema/Table.php

Lines 274 to 283 in afcd624

final public function getRenamedColumns(): array
{
return $this->renamedColumns;
}
/**
* @throws LogicException
* @throws SchemaException
*/
final public function renameColumn(string $oldName, string $newName): Column

Why

There seems to be no valid reason to make that methods final and using final methods, this makes it impossible to a) overwrite these methods and b) mock them in tests (our problem at the moment).

How

Just remove the "final" method modifier here:

dbal/src/Schema/Table.php

Lines 274 to 283 in afcd624

final public function getRenamedColumns(): array
{
return $this->renamedColumns;
}
/**
* @throws LogicException
* @throws SchemaException
*/
final public function renameColumn(string $oldName, string $newName): Column

@derrabus
Copy link
Member

To be honest, I don't find this kind of issue very constructive. The fact that you don't know the reason behind a developer's decision, does not mean that there is "no valid reason" for that decision or that said decision "makes no sense". Just as you probably wouldn't be happy about being told that mocking a state representation of a 3rd party package such as the Table class makes no sense and that there's no valid reason to create such a mock.

@aimeos
Copy link
Contributor Author

aimeos commented Oct 25, 2024

Sorry for my ignorance questioning that decision. What is the reason behind using final for those two methods only?

@morozov
Copy link
Member

morozov commented Dec 13, 2024

We are trying to keep the external API surface to the necessary minimum to reduce the amount of effort required for maintenance.

@greg0ire
Copy link
Member

Regarding the "only" part, that's because they were added after the other methods, that were historically not final. Removing final is not a breaking change, but adding it is.

@aimeos
Copy link
Contributor Author

aimeos commented Dec 16, 2024

@morozov @greg0ire Thank you for your explanation!

Nevertheless, adding final to a public class method doesn't reduce the API surface and maintenance as the method can be used by everyone which makes it impossible to change its name, parameters or return value without breaking external code (and therefore, introduce a new major version).

According to https://ocramius.github.io/blog/when-to-declare-classes-final/, final should only be used if there's an interface which contains all public methods of the class, so at the moment, using final for those two class methods only makes testing with PHPUnit using stubs impossible.

@greg0ire
Copy link
Member

Nevertheless, adding final to a public class method doesn't reduce the API surface and maintenance as the method can be used by everyone which makes it impossible to change its name, parameters or return value without breaking external code (and therefore, introduce a new major version).

That's where you are wrong. For instance, this is a breaking change for extending types:

-protected function();
+protected function(): int;

add the final keyword, and it no longer is a breaking change:

-final protected function();
+final protected function(): int;

Having the possibility to do such a change in the future could be handy in case generics are introduced, for instance.

According to https://ocramius.github.io/blog/when-to-declare-classes-final/, final should only be used if there's an interface which contains all public methods of the class, so at the moment, using final for those two class methods only makes testing with PHPUnit using stubs impossible.

Then don't use stubs? It's not like creating a Table is hard, is it? Not only is it easy, it's IMO a better practice than using a stub for something you do not own (as already pointed out by @derrabus).

@morozov
Copy link
Member

morozov commented Dec 16, 2024

Another problem with non-final methods is that, if we deprecate one, we need to have the framework use it until the next major release, because if it's overridden, then no longer calling it is a BC break.

Eventually, all subclasses of AbstractAsset will become proper value objects (final and immutable). To test against a given value, one needs to construct it.

@aimeos
Copy link
Contributor Author

aimeos commented Dec 17, 2024

Another problem with non-final methods is that, if we deprecate one, we need to have the framework use it until the next major release, because if it's overridden, then no longer calling it is a BC break.

You can't remove public methods (final or not) without a BC break.

@greg0ire
Copy link
Member

Where did you read anything about removing a method?

@aimeos
Copy link
Contributor Author

aimeos commented Dec 17, 2024

Public class methods belong to the external API and can be used by consumers of the API, so any removal of a public class method is a BC break

@greg0ire
Copy link
Member

Yes, but nobody here said anything about removing them.

@aimeos
Copy link
Contributor Author

aimeos commented Dec 17, 2024

Another problem with non-final methods is that, if we deprecate one, we need to have the framework use it until the next major release, because if it's overridden, then no longer calling it is a BC break.

Here

@greg0ire
Copy link
Member

greg0ire commented Dec 17, 2024

No? This is about being able to stop calling the deprecated method… what makes you think it's about removing it?

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