PHP code example of dave-liddament / php-language-extensions

1. Go to this page and download the library: Download dave-liddament/php-language-extensions library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

dave-liddament / php-language-extensions example snippets



class Person
{
    #[Friend(PersonBuilder::class)]
    public function __construct()
    {
        // Some implementation
    }
}


class PersonBuilder
{
    public function build(): Person
    {
        $person = new Person(): // OK as PersonBuilder is allowed to call Person's construct method.
        // set up Person
        return $person;
    }
}


// ERROR Call to Person::__construct is not from PersonBuilder
$person = new Person();

 
  #[Friend(Foo::class)]
  class Entity
  {
    public function ping(): void // ping has friend Bar
    {
    }
  }
  
 
  #[Friend(Foo::class)]
  class Entity
  {
    #[Friend(Bar::class)] 
    public function pong(): void // pong has friends Foo and Bar
    {
    }
  }
  

namespace Foo {

  class Telephone 
  {
    #[NamespaceVisibility]
    public function ring(): void
    {
    }
  }

  class Ringer
  {
    public function ring(Telephone $telephone): Person
    {
      $telephone->ring(); // OK calling Telephone::ring() from same namespace
    }
  }
}

namespace Foo\SubNamespace {

  use Foo\Telephone;
  
  class SubNamespaceRinger
  {
    public function ring(Telephone $telephone): Person
    {
      $telephone->ring(); // OK calling Telephone::ring() from sub namespace
    }
  }
}


namespace Bar {

  use Foo\Telephone;
  
  class DifferentNamespaceRinger
  {
    public function ring(Telephone $telephone): Person
    {
      $telephone->ring(); // ERROR calling Telephone::ring() from different namespace
    }
  }
}

namespace Foo {

  class Telephone 
  {
    #[NamespaceVisibility(excludeSubNamespaces: true)]
    public function ring(): void
    {
    }
  }

}

namespace Foo\SubNamespace {

  use Foo\Telephone;
  
  class SubNamespaceRinger
  {
    public function ring(Telephone $telephone): Person
    {
      $telephone->ring(); // ERROR - Not allowed to call Telephone::ring() from a sub namespace
    }
  }
}

namespace Foo {

  class Telephone 
  {
    #[NamespaceVisibility(namespace: "Bar")]
    public function ring(): void
    {
    }
  }
  
  class Ringer 
  {
    public function ring(Telephone $telephone): void
    {
      $telephone->ring(); // ERROR - Can only all Telephone::ring() from namespace Bar
    }
  }
}

namespace Bar {

  use Foo\Telephone;
  
  class AnotherRinger
  {
    public function ring(Telephone $telephone): void
    {
      $telephone->ring(); // OK - Allowed to call Telephone::ring() from namespace Bar
    }
  }
}

namespace Foo {

  #[NamespaceVisibility()]
  class Telephone 
  {
    public function ring(): void // This method has NamespaceVisibility
    { }
  }
}

namespace Foo {

  #[NamespaceVisibility(namespace: 'Bar')]
  class Telephone 
  {
    #[NamespaceVisibility(namespace: 'Baz')]
    public function ring(): void // This method can only be called from the namespace Baz
    { }
  }
}


#[InjectableVersion]
class PersonRepository {...} // This is the version that should be type hinted in constructors.

class DoctrinePersonRepository extends PersonRepository {...}

class PersonCreator {
    public function __construct(
        private PersonRepository $personRepository, // OK - using the injectable version
    )
}
class PersonUpdater {
    public function __construct(
        private DoctrinePersonRepository $personRepository, // ERROR - not using the InjectableVersion
    )
}


#[InjectableVersion]
interface Validator {...} // This is the version that should be type hinted in constructors.

class NameValidator implements Validator {...}
class AddressValidator implements Validator {...}

class PersonValidator {
    /** @param Validator[] $validators */
    public function __construct(
        private array $validators, // OK - using the injectable version
    )
}


#[InjectableVersion]
interface Logger {...}

class FileLogger implements Logger {...}

class MyService 
{
    #[CheckInjectableVersion]
    public function setLogger(Logger $logger): void {} // OK - Injectable Version injected
    
    public function addLogger(FileLogger $logger): void {} // No issue raised because addLogger doesn't have the #[CheckInjectableVersion] attribute.
}



#[Sealed([Success::class, Failure::class])]
abstract class Result {} // Result can only be extended by Success or Failure

// OK
class Success extends Result {}

// OK
class Failure extends Result {}

// ERROR AnotherClass is not allowed to extend Result
class AnotherClass extends Result {}

class Person {

    #[TestTag]
    public function setId(int $id) 
    {
      $this->id = $id;
    }
}


function updatePersonId(Person $person): void 
{
    $person->setId(10);  // ERROR - not test code.
}


class PersonTest 
{
    public function setup(): void
    {
        $person = new Person();
        $person->setId(10); // OK - This is test code.
    }
}