Giter Club home page Giter Club logo

psl's Introduction

Important

🇵🇸 Support Palestine 🇵🇸

In light of recent events in Gaza, I encourage everyone to educate themselves on the ongoing issues in Palestine and consider supporting the people there. Here are some resources and donation links:

Thank you for taking a moment to bring awareness and make a difference. 🇵🇸❤️

Psl - PHP Standard Library

Unit tests status Static analysis status Security analysis status Coding standards status Coding standards status CII Best Practices Coverage Status MSI Type Coverage Total Downloads Latest Stable Version License

Psl is a standard library for PHP, inspired by hhvm/hsl.

The goal of Psl is to provide a consistent, centralized, well-typed set of APIs for PHP programmers.

Example

<?php

declare(strict_types=1);

use Psl\Async;
use Psl\TCP;
use Psl\IO;
use Psl\Shell;
use Psl\Str;

Async\main(static function(): int {
    IO\write_line('Hello, World!');

    [$version, $connection] = Async\concurrently([
        static fn() => Shell\execute('php', ['-v']),
        static fn() => TCP\connect('localhost', 1337),
    ]);

    $messages = Str\split($version, "\n");
    foreach($messages as $message) {
        $connection->writeAll($message);
    }

    $connection->close();

    return 0;
});

Installation

Supported installation method is via composer:

composer require azjezz/psl

Psalm Integration

Please refer to the php-standard-library/psalm-plugin repository.

PHPStan Integration

Please refer to the php-standard-library/phpstan-extension repository.

Documentation

You can read through the API documentation in docs/ directory.

Interested in contributing?

Have a look at CONTRIBUTING.md.

Sponsors

Thanks to our sponsors and supporters:

JetBrains

License

The MIT License (MIT). Please see LICENSE for more information.

psl's People

Contributors

azjezz avatar backendtea avatar bcremer avatar caugner avatar danack avatar dependabot-preview[bot] avatar dependabot[bot] avatar devnix avatar dragosprotung avatar gashmob avatar gsteel avatar hasseneb avatar hvt avatar ineifar avatar jrmajor avatar kennedytedesco avatar michaelpetri avatar ntzm avatar nzour avatar ocramius avatar ondrejmirtes avatar orklah avatar simpod avatar stof avatar vaclavvanik avatar veewee avatar weirdan avatar yivi avatar zerkms avatar zerogiven avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

psl's Issues

refactoring Arr and Iter

Arr and Iter components are currently confusing, with some functions being pure, and other not, some returning lists, dicts, or just a value/key, or something else.

The idea would be:

  1. Iter would contain generic array functions that operate on all iterables, and usually don't return an iterable ( e.g: Iter\first, Iter\count, Iter\contains, Iter\contains_key .. etc )
  2. a new component Vec should contain every function that returns a vec ( i.e list ) from both Arr and Iter.
  3. a new component Dict should contain every function that returns a dict ( i.e array<Tk, Tv> ) from both Arr and Iter
  4. deprecate Arr component ( all functions will be move to either Iter, Vec, or Dict )

This also means that we lazy loaded iterators, however, i don't see that as an issue, most functions will still accept iterables, so you can provide a generate, and wrap the result in a generator your self.

However, this doesn't solve the pure issue, where functions are not considered pure, but after #119, we can extend the psalm plugin to make it so Vec\sort($array) considered pure, while Vec\sort($db->getUsers()) ( where $db->getUsers() returns a mutable traversal ) considered impure.

Not installable without ARGON2 support

Is your feature request related to a problem? Please describe.
Hi there,

This library is not install-able unless argon2 support has been compiled into php.

Otherwise, we will receive:

PHP Fatal error:  Uncaught Error: Undefined constant 'PASSWORD_ARGON2I'

Describe the solution you'd like
Would you be open to conditionally supporting the argon2 password hashing, only if argon 2 support is available?

I want to use the iter/arr methods of this library - i don't really care about not having argon2 support.

Describe alternatives you've considered
compile in argon2 support before requiring psl.

rework exceptions

we should refactor all of our exceptions, and use error instead where it makes sense.

  • move exceptions from Exception namespace to Throwable namespace in all components.
  • extend Error instead of Exception in InvariantViolationException ( and rename to InvariantViolation ) - #308

Objects API

The Obj component should contain functions that are related to objects, or OOP in general.

examples ( not sure about the naming yet ):

  • Psl\Obj\contains_method($object, $method): bool
  • Psl\Obj\contains_property($object, $property): bool
  • Psl\Obj\class_exists($classname): bool ( always triggers the autoloader )
  • pure Psl\Obj\class_included($classname): bool ( never triggers the autoloader )
    ...

Shell component

Introduce a shell component containing a replacement for the following PHPs builtin shell functions:

  • escapeshellarg ( Psl\Shell\escape_argument )
  • escapeshellcmd ( Psl\Shell\escape_command )
  • exec, shell_exec ( Psl\Shell\execute )

Psl\Shell\execute must always return a string, containing the full output, if the command returned a non 0 exist code, an exception should be thrown.

The thrown exception should contain all information that the end user might need ( e.g: $exception->getCommand(), $exception->getExitCode(), $exception->getOutput() .. etc )

Union for variadic types

There are a lot of situations may occur when we need to define union from several cases.
For example: need to define enum of states.

This would look like:

use Psl\Type as T;

$codec = T\shape([
    // ... rest of fields
    'state' => T\union(
        T\literal_scalar('NEW'),
        T\union(
            T\literal_scalar('APPROVED'),
            T\union(
                T\literal_scalar('REJECTED'),
                T\union(
                    T\literal_scalar('COMPLETED'),
                    T\union(
                        T\literal_scalar('FROZEN'),
                        T\literal_scalar('ERROR')
                    )
                )
            )
        )
    ),
]);

Inferred type would be:

array{id: string, state: "APPROVED"|"COMPLETED"|"ERROR"|"FROZEN"|"NEW"|"REJECTED"}

I guess it would be great to have better solution like:

use Psl\Type as T;

$codec = T\shape([
    'id' => T\string(),
    'state' => T\union_of(
        T\literal_scalar('NEW'),
        T\literal_scalar('APPROVED'),
        T\literal_scalar('REJECTED'),
        T\literal_scalar('COMPLETED'),
        T\literal_scalar('FROZEN'),
        T\literal_scalar('ERROR'),
    ),
]);

I do understand that Psl\Type\Internal\UnionType has only 2 branches: left and right
That's why propose just implement a function with signature:

/**
 * @template T
 *
 * @param TypeInterface<T> $left_type
 * @param TypeInterface<T> $right_type
 * @param TypeInterface<T> ...$others
 * @return TypeInterface<T>
 *
 * @no-named-arguments
 */
function union_of(
    TypeInterface $left_type,
    TypeInterface $right_type,
    TypeInterface ...$others
): TypeInterface { // actually Psl\Type\Internal\UnionType returns here
    ...
}

As alternatives I may guess there is more suitable name for function.
This may be named like literals or one_of or etc.

This function may also be implemented in user land, but I think it would be great to have unified solution inside core of the library.


Want to hear other guys thoughts.
If this would be approved, I may produce PR.
As I can see, this is very light enhancement.

Filesystem component

Introduce a filesystem component containing a replacement for the following PHPs builtin filesystem functions:

  • basename ( Psl\Filesystem\basename )
  • chgrp ( Psl\Filesystem\chgrp )
  • chmod ( Psl\Filesystem\chmod )
  • chown ( Psl\Filesystem\chown )
  • copy ( Psl\Filesystem\copy )
  • dirname ( Psl\Filesystem\dirname )
  • file_​exists ( Psl\Filesystem\file_exists )
  • glob ( Psl\Filesystem\glob )
  • is_​dir ( Psl\Filesystem\is_dir )
  • is_​executable ( Psl\Filesystem\is_executable )
  • is_​file ( Psl\Filesystem\is_file )
  • is_​link ( Psl\Filesystem\is_link )
  • is_​readable ( Psl\Filesystem\is_readable )
  • is_​writable ( Psl\Filesystem\is_writable )
  • lchgrp ( Psl\Filesystem\link_chgrp )
  • lchown ( Psl\Filesystem\link_chown )
  • link ( Psl\Filesystem\link )
  • mkdir ( Psl\Filesystem\mkdir )
  • realpath ( Psl\Filesystem\realpath )
  • rename ( Psl\Filesystem\rename )
  • rmdir ( Psl\Filesystem\rmdir )
  • symlink ( Psl\Filesystem\symlink )
  • touch ( Psl\Filesystem\touch )
  • unlink ( Psl\Filesystem\unlink )

Documentation

We should probably have documentation that people can use to lookup functions and their descriptions + a couple of examples.

add pseudo random functions

the Random component currently implements cryptographically secure random functions, these should be moved to the SecureRandom namespace, while adding pseudo-random functions under PseudoRandom namespace.

i.e

function float(): float {
  return (float)(namespace\int(0, Math\INT53_MAX - 1) / Math\INT53_MAX);
}

function int(int $min = Math\INT53_MIN, int $max = Math\INT53_MAX): int {
  return mt_rand($min, $max);
}

[DataStructure] iterating over data structures

see discussion in #53 ( #53 (comment) )

Questions:

  • should you be able to iterate over a data structure ( queue, stack .. etc)
  • should values be removed from the DS when iterating over them?
  • should values pushed while iterating the DS be consumed in the same loop?

[Str] add `after` and `before` helpers

add after{_ci|_last{_ci}} and before{_ci|_last{_ci}} helper string functions.

We should implement these functions for Psl\Str, Psl\Str\Byte, and Psl\Str\Grapheme ( refs #74 ), which totals to a new 24 functions.

Psl\Str implementations would have an extra argument ?string $encoding = null.

function after(string $haystack, string $needle, bool $include_needle = false, int $offset = 0): string;

function after_ci(string $haystack, string $needle, bool $include_needle = false, int $offset = 0): string;

function after_last(string $haystack, string $needle, bool $include_needle = false, int $offset = 0): string;

function after_last_ci(string $haystack, string $needle, bool $include_needle = false, int $offset = 0): string;

function before(string $haystack, string $needle, bool $include_needle = false, int $offset = 0): string;

function before_ci(string $haystack, string $needle, bool $include_needle = false, int $offset = 0): string;

function before_last(string $haystack, string $needle, bool $include_needle = false, int $offset = 0): string;

function before_last_ci(string $haystack, string $needle, bool $include_needle = false, int $offset = 0): string;

Vec\sum()?

I see that there is no array_sum() equivalent provided.

Is this intentional, or is something that you'd be willing to consider?

Html component

Add html component that contains functions to replace the following PHP builtin functions:

  • html_​entity_​decode
  • htmlentities
  • htmlspecialchars_​decode
  • htmlspecialchars

I/O, File, and Network API

  • IO handles ( done - #127 )
    • File handles ( done - #250 )
    • Network handles ( done - #257 )
      • Socket handle
      • Server Interface
      • TCP
        • TCP Sockets
        • TCP Server
      • UDP
        • UDP Sockets
        • UDP Server

Generator functions

All functions within Psl\Iter that return Generator should be moved to Psl\Gen.

A wrapper for Psl\Iter should be created to return Psl\Iter\Iterator instead of a generator ( i.e a rewindable, seekable iterator )

Filesystem - read_file - InvariantViolationException message should contains filename

Is your feature request related to a problem? Please describe.

When I try to read_file which does not exist, is not file or is not readable InvariantViolationException is thrown with message like $file does not exist.

I would like to see given filename in exception message. It's than easier to debug and fix possible problem.

Describe the solution you'd like

Replace

Psl\invariant(exists($file), '$file does not exist.');

with

Psl\invariant(exists($file), Str\format('File "%s" does not exist.', $file));

Thrown RuntimeException contains provided $file too.

`Psl\Type\non_empty_string()` is not marked as `@psalm-pure`?

In the context of following snippet:

    /**
     * @throws InvalidPackageName
     *
     * @psalm-pure
     */
    public static function fromName(string $name): self
    {
        if (preg_match('{^[a-z0-9](?:[_.-]?[a-z0-9]+)*/[a-z0-9](?:(?:[_.]?|-{0,2})[a-z0-9]+)*$}iD', $name) !== 1) {
            throw InvalidPackageName::fromInvalidName($name);
        }

        return new self(
            non_empty_string()
                ->coerce($name)
        );
    }

psalm reports:

... Cannot call an impure function from a mutation-free context (see https://psalm.dev/202)
            non_empty_string()

I wonder if all type constructors can/should be declared pure? Is this where we got stuck on conditional type purity?

[Str] Grapheme support

Just like Psl\Str\Byte component, we want to add Psl\Str\Grapheme that wraps grapheme_str* function in a nicer API that is consistent with our Psl\Str and Psl\Str\Byte components.

[Type] Coerce float to string

Currently, it is not possible to convert a float -> string.

public function coerce($value): string

The other way around (string -> float) is possible.

We could go for one of these solutions to make it possible in a locale-safe way:

Would it make sense to add it and do you see any additional risks?

Quality Assurance tools integration.

This is a meta issue to keep track of which QA tools are being used in PSL, the end goal is to have all these tools ( and more hopefully ) integrated with PSL and as part of our CI. ( PRs welcome! )

Coding Standards

Tool Description Integrated
php-cs-fixer PHP Coding Standards Fixer
php_codesniffer ✔️

There's a lot of rules we have that are currently not enforced by CI:

  • a file can only contain 1 function declaration
  • Psl\Foo\Bar\Baz\qux function must be declared in src/Psl/Foo/Bar/Baz/qux.php
  • function name must be in snake_case
  • argument name must be in snake_case
  • constant Psl\Foo\Bar\BAZ_QUX must be declared in src/Psl/Foo/Bar/constants.php
  • all classes should be declared either final or abstract ( unless its an exception )
  • interface names should end with Interface suffix
  • abstract classes should have the Abstract prefix
  • traits should end with Trait suffix
  • closure should always be declared static, even within functions, when $this is not used.

Static Analysis

Tool Description Integrated Coverage
PSalm Static Analysis tool. 100%
PHPStan Static Analysis tool. 0%
SymfonyInsight PHP project quality, done right. n/a
php-assumptions Tool to detect assumptions n/a?
phpmd n/a?

Testing

Tool Description Integrated Coverage
PHPUnit Unit Testing framework. 100%

Security

Tool Description Integrated
RoaveSecurityAdvisories Security advisories as a simple composer exclusion list.
SymfonoySecurity PHP security vulnerabilities monitoring.
Psalm ( taint analysis ) Static Analysis tool.

Dependabot can't resolve your PHP dependency files

Dependabot can't resolve your PHP dependency files.

As a result, Dependabot couldn't update your dependencies.

The error Dependabot encountered was:

Your requirements could not be resolved to an installable set of packages.
  Problem 1
    - Root composer.json requires php-standard-library/psalm-plugin ^1.0 -> satisfiable by php-standard-library/psalm-plugin[1.0.0].
    - php-standard-library/psalm-plugin 1.0.0 requires azjezz/psl ^1.5 -> satisfiable by azjezz/psl[1.5.0] from composer repo (https://repo.packagist.org) but azjezz/psl[1.0.0+no-version-set] from root package repo has higher repository priority. The packages with higher priority do not match your constraint and are therefore not installable. See https://getcomposer.org/repoprio for details and assistance.

If you think the above is an error on Dependabot's side please don't hesitate to get in touch - we'll do whatever we can to fix it.

View the update logs.

Join forces?

Hello,

Today I landed on this repository. It looks very similar with something I am creating:
https://github.com/veewee/happy-helpers

Feel free to check it out.

There are:

  • many simalar approaches: iterables, predicates, ...
  • some other approaches like: results
  • some additional things like xml, dom, callables, ...

Besides what is in there, I also put some thought in stuff like file resources, but nothing concrete.

My intention of that package was mostly learning, but I am using it in some of my private projects and would love to introduce a far more advanced version in customer projects. I was not planning of putting a lot of extra features in there at the moment.

Since this package is very in-line with wath I am doing and since it is far more mature, I'dd be willing to merge/donate them to this project.

Let me know if you are interested! We can always have a chat if you're up to it.

Dependabot can't resolve your PHP dependency files

Dependabot can't resolve your PHP dependency files.

As a result, Dependabot couldn't update your dependencies.

The error Dependabot encountered was:

Your requirements could not be resolved to an installable set of packages.
  Problem 1
    - Root composer.json requires php-standard-library/psalm-plugin ^1.0 -> satisfiable by php-standard-library/psalm-plugin[1.0.0].
    - php-standard-library/psalm-plugin 1.0.0 requires azjezz/psl ^1.5 -> satisfiable by azjezz/psl[1.5.0] from composer repo (https://repo.packagist.org) but azjezz/psl[1.0.0+no-version-set] from root package repo has higher repository priority. The packages with higher priority do not match your constraint and are therefore not installable. See https://getcomposer.org/repoprio for details and assistance.

If you think the above is an error on Dependabot's side please don't hesitate to get in touch - we'll do whatever we can to fix it.

View the update logs.

PHP 5.6 Support

Is your feature request related to a problem? Please describe.
For some of our important projects, we need to use PHP 5.6 for comparability with the customers' environments.

Describe the solution you'd like
Any information on what it would take to use psl within a PHP 5.6 project.

Describe alternatives you've considered
Writing some of the functions we need ourselves over time. This library is much better.

Thank you to the creators and maintainers of psl.

[Tests] missing static analysis

Currently, tests are now being type-checked, but it would be nice if we do type check everything within PSL, tests included.

support for non-empty-array/non-empty-list

Hi there!

Is your feature request related to a problem? Please describe.

Is is feasible to

  1. add non-empty-array and non-empty-list support to the type system, such that:
  2. the return Psl\Iter\first and other functions can be T and not T|null?

Describe the solution you'd like
I want to be able to do things like:

<?php

declare(strict_types=1);

use Psl;

class FooExtractor
{
    /** @param list<Foo> $foos */
    public function __invoke(array $foos): Foo
    {
        $foosFiltered = Vec\filter(
            $foos,
            function (Foo $foo): bool {
                ...
            }
        );

        //assert $foosFiltered type is non-empty-list/array here.

        //this will error as the return type is `T|null`
        return Iter\first($foosFiltered);
    }
}

Is there a better way to achieve what I'm trying to do?

Thanks!

Introduce benchmark + performance regression checks

As Psl\ grows in size and adoption, its performance becomes one important evaluation point when considering it for downstream adoption.

This question came up in both #194 and Roave/BackwardCompatibilityCheck#306, and it would be a good idea to have reference/comparison.

The idea is to have following benchmarks:

  • comparison of Psl and internal functions or constructs it replaces (assuming 100% type coverage and no runtime errors occur)
  • comparison of Psl against itself at different releases

For that, it would be interesting to use https://github.com/phpbench/phpbench/tree/1.0.1

@dantleech do you know if there is a sensible way to run benchmarks and compare them in CI? That's something that is kinda missing within PHPBench' docs 🤔

Performance of reimplemented functions?

I understand that a completely reimplemented function in userland code will be slower than the compiled C counterpart, yet I thought that for many functions PSL simply implemented a wrapper for native functions, thus having little overhead.

I got a little surprised when I was replacing some instances of \array_unique of suddenly getting a measurable drop in performance (those are rather large arrays, but that's what I get).

Here I can replicate it with this code:

$arr = [];
$iterations   = 10;
$array_size   = 1000;
$random_range = 5000;

for ($i = 0; $i < $array_size; $i++) {
    $arr[] = Psl\SecureRandom\int(0, $random_range);
}

$total = 0;
$ta0 = microtime(true);
for ($e = 0; $e < $iterations; $e++) {
    $total += \count(\array_unique($arr));
}
$ta1 = microtime(true);

echo "Native\n";
echo $total / $iterations, "\n";
echo 'Time: ' . round($ta1 - $ta0, 4), "\n\n";

$total = 0;
$ta0   = microtime(true);
for ($e = 0; $e < $iterations; $e++) {
    $total += \Psl\Iter\count(\Psl\Dict\unique($arr));
}
$ta1 = microtime(true);

echo "Psl\n";
echo $total / $iterations, "\n";
echo 'Time: ' . round($ta1 - $ta0, 4);

The result in this case is 0.0009 seconds for native implementations, against 0.0841 seconds for using Psl. True, for this case 0,08 seconds is still something I can live with, but it's still a very marked cost increase. For my particular use case can even become problematic.

Is this what's expected, or I'm using the library incorrectly? Mind, this is not in no way a complaint, I love the library even if this is a tradeoff to be aware of, but just wanted to be sure this was not me "holding it wrong".

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.