I got a problem with abstract class. Currently i use abstract class runnable to determine what my API need to work.
abstract class runnable {
abstract protected function __setConfig();
abstract public function __run(api $api);
public function run(api $api){
$this->__setConfig();
$this->__run($api);
}
}
I haven't got problem with this, but when i miss one method i got this fatal error:
Fatal error: Class MyClass contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (runnable::__setConfig)
I would like know how i can test if runnable's conditions are met before instanciate MyClass, i have tried with ReflectionClass::isInstantiable but i get again this error...
$reflectionClass = new ReflectionClass($appName);
if($reflectionClass->IsInstantiable()) {
// OK
} else {
// Cutom error
}
How i can make it properly?
Thank you for your help.
You can't, as soon you extend your class to an abstract it will throw an error if it doesn't contain's the methods ( even before initiate the class ).
You can't do it with reflection because is for reflection alone as the name states.
You can try to hack it with runkit , it should be the only way to do what you want.
But in the end i don't really know why you should need to do this, why don't you just extend it to a normal class instead of a abstract one? ( if you don't really care about it )
For this case you might create an Interface something like that:
interface runnableInterface {
public function run(api $api);
public function setConfig();
}
abstract class runnableAbstract implement runnableInterface {
public function run(api $api){
$this->setConfig();
$this->run($api);
}
}
class runnable extends runnableAbstract implement runnableInterface {
public function setConfig() {
// do something here
};
public function run(api $api){
$this->setConfig();
$this->run($api);
}
}
Also you can read Object Interfaces and Class Abstraction
Related
I was wondering if you could help me with the following question. First of all, I would like to tell you that if I am asking this question here, it is because I have already tried many options and none have worked for me. It turns out that I am developing a package with Laravel and I am using Laravel's dependency injection. But I am at a crossroads from which I have not found a way out. I'm trying to get the instance of a class in an intermediate method from a method chain, let me explain. Here is the code very similar to what I have:
PackageServiceProvider.php
<?php
class PackageServiceProvider extends ServiceProvider
{
public function register()
{
$this->configureBindings();
}
private function configureBindings()
{
$this->app->when(A_Class::class)->needs(B_Interface::class)->give(function () {
return new B_Class();
});
}
...
A_Class.php
<?php
class A_Class implements A_Interface
{
private $b_interface;
public function __construct(B_Interface $b_interface)
{
$this->b_interface = $b_interface;
}
public function create($arg1, $arg2)
{
return $this->b_interface->method_1()->call_another_method_from_another_class();
}
}
A_Interface.php
<?php
interface A_Interface extends Arrayable, Rendereable
{
public function create($arg1, $arg2);
...
}
<?php
class B_Class implements B_Interface
{
public function __construct()
{
// Here is the question...
// How could I get here the instance of the class A_Class?
}
public function method_1()
{
// should return another class instance
}
public function method_2()
{
// should return another class instance
}
}
B_Interface.php
<?php
interface B_Interface
{
public function method_1();
public function method_2();
...
}
If you look at class B_Class``, in the __constructmethod I'm trying to get the instance of classA_Class``` from where that class is being called. I have tried the following:
class B_Class implements B_Interface
{
public function __construct(A_Interface $a_interface)
{
// Here is the question...
// How could I get here the instance of the class A_Class?
}
But I get the following error:
Segmentation fault
I guess there must be some way I can achieve what I need. I would appreciate any help in advance.
Because you are referring to class A inside your class B constructor, and class B in your class A constructor, you have introduced a cyclic dependency.
This will resolve to the error you are experiencing, which is the segmentation fault, as outlined here:
https://laravel.io/forum/11-08-2016-circular-dependency-causes-segmentation-fault-error-when-running-php-artisan-optimize
So the answer is to remove the cyclic dependency if possible, as you can have methods from A calling B that calls A for infinity at runtime, and you will get the above error above again.
If your class A and B are relatively small, I would recommend combining them before using a cyclic dependency.
For interest and prosperity, if you want achieve a cyclic dependency, this is possible by registering your Class A with a singleton from inside A's constructor, and putting the reference to the incomplete object into Class B with your code above. I try with laravels singleton here, its untested, but hopefully you'll get the idea.
class A_Class implements A_Interface
{
public function __construct(B_Interface $b_interface)
{
//I dont think you can pass $this to a function when construction is incomplete, hence $that.
$that = $this;
App::singleton('A_Class', function($that){
return $that;
});
$this->b_interface = $b_interface;
}
}
class B_Class implements B_Interface
{
public function __construct(A_Interface $a_interface)
{
//unfinished object, but no more error.
$this->aClass = App::make('A_Class')
}
}
I have a PHP core with an abstract class AppBase which use a trait Uninstall.
To force developper to implement a static function to delete some options inside the main class MyApp, the AppBase implements an interface with a static function 'delete_options()'.
AppBase
abstract class AppBase implements iUninstall{
use Uninstall;
}
Uninstall
trait Uninstall{
public static function uninstall(){
//Do some general stuff
self::delete_options();
}
}
iUninstall
interface iUninstall {
public static function delete_options();
}
MyApp
include_once "core/iUninstall.php";
include_once "core/Uninstall.php";
include_once "core/AppBase.php";
class MyApp extends AppBase{
public static function delete_options() {
delete_option( "first-option" );
delete_option( "second-option" );
}
}
My problem is I got this error:
PHP Fatal error: Uncaught Error: Cannot call abstract method iUninstall::delete_options() in Uninstall.php
I can see the trait Uninstall must be attached to AppBase to use delete_options so there is a matter in my OOP architecture.
How can I resolve this ?
First off, you should have gotten a fatal error about AppBase having an abstract method delete_options() while not being an abstract class. So, you need to make AppBase an abstract class. (But perhaps you had just forgotten to copy that into your example.)
Then, in Uninstall::uninstall() you need to use static instead of self (to utilize late static binding).
So, to wrap it up:
trait Uninstall {
public static function uninstall(){
// static instead of self
static::delete_options();
}
}
interface iUninstall {
public static function delete_options();
}
// abstract class instead of class
abstract class AppBase implements iUninstall{
use Uninstall;
}
class MyApp extends AppBase {
public static function delete_options() {
echo 'deleting';
}
}
MyApp::uninstall();
/* result:
deleting
*/
Or... you could just implement delete_options() as a (stub) method in AppBase, but there was no indication in your question that that was your original intent.
view online parsed # eval.in
Hello i have a problem,
with my code, i don't know what im fix this code
Error
Fatal error: Class Group contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (Aturan::cari) in D:\xampp\htdocs\tes\index.php on line 16
This is my code
<?php
interface Aturan {
public function cari($id);
}
trait Bantuan {
public function ubah_ke_string_json($str){
return NULL;
}
}
abstract class Aturan_abstrak implements Aturan {
use Bantuan;
}
class Group extends Aturan_abstrak {
protected $grup;
public function Group($grup) {
$this->grup = $grup;
}
}
$grup = new Group(array(
"C" => array("administrator"),
"A" => array("operator","staff")
));
echo $grup->cari("A");
?>
i'm confused, help me please.
This error means, that one or more abstract methods needs to be implemented first. In your case, method cari is not implemented.
Please take a look at topic Class Abstraction for more information.
This code fails. But I don't understand why. If I change the function lol to function anything else, it works. If I change the class of the Abstract it also works. See this execution: http://codepad.viper-7.com/Z9V67x
<?php
abstract class Lol{
abstract public function lol($external = false);
}
class Crazy extends Lol{
public function lol($external = false){
echo 'lol';
}
}
$new = new Crazy;
$new->lol('fdgdfg');
The error that comes back is:
Fatal error: Cannot call abstract method Lol::lol() in /code/Z9V67x on line 17
PHP Fatal error: Cannot call abstract method Lol::lol() in /code/Z9V67x on line 17
Doing some research on same name functions and classes, in PHP4 the same name meant a constructor. According to this https://stackoverflow.com/a/6872939/582917 answer, namespaced classes no longer treated functions with the same name as the constructor. BUt non namespaced classes do. Still why can't the constructors be replaced in the child instance?
check code below:
abstract class Lol{
public function __construct() { // only one constructor is really needed
}
abstract public function lol($external = false);
}
class Crazy extends Lol{
public function __construct() { // only one constructor is really needed
}
public function Crazy() { // only one constructor is really needed
}
public function lol($external = false) {
echo 'lol';
}
}
$new = new Crazy();
$new->lol('fdgdfg');
it works ok, why?
PHP is not very good with OOP, even latest version, it has PHP4 legacy, so lets try to understand what your code do:
it defined abstract function, which is understand by php as constructor and as abstract method
in sub class you're defining only method, but constructor is still abstract
this is why you're getting error during new - php really cannot find constructor
now check code above - it has 3 constructors, you can have any 1 and this code will work
Here is an example of my class structure for a data mapping pattern (simplified). Notice that the save and find methods are technically implemented in the concrete class, but do not do anything yet. What alternatives are there to avoid this? One option I am currently using is an abstract DataMapperAbstract class that implements the interface, throws an exception for every method, then all concrete data mappers only have to implement the functions they use - it just smells bad. Personally, I have thought of creating a separate interface for each method (DataMapper_FindInterface, DataMapper_SaveInterface, DataMapper_DeleteInterface, etc.) but it seems a bit smelly.
interface DataMapperInterface
{
public function find($params);
public function save($object);
public function delete($object);
}
class DataMapper_User implements DataMapperInterface
{
public function find($params)
{
//Execute code to retrieve data from data source
return someDataRetrievalMethod($params);
}
public function save($object)
{
throw new Exception('Method not yet implemented.');
}
public function delete($object)
{
throw new Exception('Method not yet implemented.');
}
}
As long as you are not in the class that has al methods implement, make the class abstract.
Abstract classes can not be instantiated, and there must be another class thats extends the abstract class with a implementation.
So your code so far would look like this:
interface DataMapperInterface
{
public function find($params);
public function save($object);
public function delete($object);
}
abstract class DataMapper_User implements DataMapperInterface
{
public function find($params)
{
//Execute code to retrieve data from data source
return someDataRetrievalMethod($params);
}
}