Upgrade to Pro — share decks privately, control downloads, hide ads and more …

What's new in PHP 8.3?

What's new in PHP 8.3?

I'll show you the new features, deprecations and BC breaks of the new PHP 8.3 release with some comparing code samples and fun facts.

This talk was held at the PHP USERGROUP DRESDEN e.V. on December 14, 2023.

Holger Woltersdorf

December 14, 2023
Tweet

More Decks by Holger Woltersdorf

Other Decks in Programming

Transcript

  1. ©2023 Public. All Rights Reserved.
    PHP USERGROUP DRESDEN e.V.
    X-​
    MAS Meetup 2023
    December 14 at move elevator GmbH
    What's new in

    View full-size slide

  2. ©2023 Public. All Rights Reserved.
    Community work in numbers
    2,190
    commits
    3,254
    files changed
    November, 23
    GA release
    🥳
    83 fixed
    issues
    52 added
    improvements
    4 removals
    of obsolete or
    breaking code
    13 accepted
    RFCs, with
    ø 24,8 voters
    19 new
    Features
    32 new
    functions /
    methods
    66 new
    global
    constants
    29 breaking
    changes
    17
    deprecations
    61 other
    changes &
    improvements
    28
    contributors
    https://github.com/php/php-​
    src/compare/php-​
    8.2.13...php-​
    8.3.0 • https://www.php.net/manual/en/migration83.php • https://www.php.net/ChangeLog-​
    8.php#8.3.0 • https://php-​
    rfc-​
    watch.beberlei.de/#Accepted%20RFCs%20for%20PHP%208.3

    View full-size slide

  3. ©2023 Public. All Rights Reserved.
    NEW FEATURES

    View full-size slide

  4. ©2023 Public. All Rights Reserved.
    Readonly amendments
    Anonymous classes may now be marked as readonly
    PHP 8.2 PHP 8.3

    View full-size slide

  5. ©2023 Public. All Rights Reserved.
    Readonly amendments
    Readonly properties can now
    be reinitialized during cloning.
    This is useful for deep cloning
    of object trees.
    PHP 8.2 PHP 8.3
    Fatal error: Uncaught Error: Cannot modify readonly
    property User::$username in /in/A338W:9
    Stack trace:
    #0 /in/A338W(14): User->__clone()
    #1 {main}
    thrown in /in/A338W on line 9
    Dresden JS

    View full-size slide

  6. ©2023 Public. All Rights Reserved.
    Types class constants
    Changing the type of constants during inheritance fails
    PHP 8.2 PHP 8.3
    Fatal error: Cannot use array as value for class constant
    Foo::PHP of type string

    View full-size slide

  7. ©2023 Public. All Rights Reserved.
    Dynamic class constant fetch
    Fetch constant values in classes with less effort
    PHP 8.2 PHP 8.3

    View full-size slide

  8. ©2023 Public. All Rights Reserved.
    #​
    [\Override] Attribute
    Intentionally override a base method & fail if base method does not exist
    PHP 8.2 PHP 8.3
    Fatal error: MyTest::taerDown() has #​
    [\Override] attribute,
    but no matching parent method exists

    View full-size slide

  9. ©2023 Public. All Rights Reserved.
    json_validate()
    Check for valid JSON with less code and more efficiently
    PHP 8.2 PHP 8.3
    true true

    View full-size slide

  10. ©2023 Public. All Rights Reserved.
    Randomizer::getBytesFromString()
    Quickly generate a random string from given chars with a given length
    PHP 8.2 PHP 8.3
    random_int()
    is not seedable
    for testing, but
    secure.
    A \Random\Engine
    may be passed for
    seeding, default is the
    secure engine

    View full-size slide

  11. ©2023 Public. All Rights Reserved.
    Randomizer::getFloat() / Randomizer::nextFloat()
    Generate unbiased random float values in a given range
    PHP 8.2 PHP 8.3
    getFloat() might return
    the upper bound, i.e. 1,
    introducing a small bias
    [ 0.0, 1.0 ] [ 0.0, 1.0 )

    View full-size slide

  12. ©2023 Public. All Rights Reserved.
    Just in case you can't remember the interval notation either
    🤓
    Source: https://curvebreakerstestprep.com/what-​
    is-​
    interval-​
    notation-​
    domain-​
    range-​
    example/

    View full-size slide

  13. ©2023 Public. All Rights Reserved.
    Command line linter supports multiple files
    The CLI linter now accepts variadic input for filenames to lint
    PHP 8.2 PHP 8.3
    php -​
    l foo.php bar.php
    No syntax errors detected in foo.php
    php -​
    l foo.php bar.php
    No syntax errors detected in foo.php
    No syntax errors detected in bar.php

    View full-size slide

  14. ©2023 Public. All Rights Reserved.
    Final modifier for a trait method
    PHP 8.2
    PHP 8.3
    Fatal error: Cannot override final
    method Output::test()
    Fatal error: Cannot use 'final' as
    method modifier

    View full-size slide

  15. ©2023 Public. All Rights Reserved.
    Final modifier for a trait method
    PHP 8.2
    PHP 8.3
    Fatal error: Cannot override final
    method Output::test()
    Fatal error: Cannot use 'final' as
    method modifier
    If you like your
    project at least a
    bit: Please try
    to avoid using
    traits!
    🙏

    View full-size slide

  16. ©2023 Public. All Rights Reserved.
    Closures from magic methods accept named parameters
    PHP 8.2
    PHP 8.3
    array(1) {
    ["a"]=>
    int(123)
    }
    array(1) {
    ["a"]=>
    int(123)
    }
    array(1) {
    ["a"]=>
    int(123)
    }
    Fatal error: Uncaught Error: Unknown
    named parameter $a

    View full-size slide

  17. ©2023 Public. All Rights Reserved.
    Arbitrary static variable initializers
    PHP 8.2
    PHP 8.3
    bar() called
    1
    2
    3
    Fatal error: Constant expression
    contains invalid operations

    View full-size slide

  18. ©2023 Public. All Rights Reserved.
    Support for fallback value syntax in php.ini
    Source:
    https://php.watch/versions/8.3/php-​
    ini-​
    envar-​
    fallback-​
    value-​
    syntax
    Supported Functions
    The fallback value syntax is supported
    in all PHP functions that return, set,
    and parse INI values. This includes:
    ini_get()
    ini_get_all()
    ini_set()
    get_cfg_var()
    parse_ini_string()
    parse_ini_file()
    array(1) {
    ["name"]=>
    string(5) "MyApp"
    }
    PHP 8.3
    array(1) {
    ["name"]=>
    string(0) ""
    }
    PHP 8.2

    View full-size slide

  19. ©2023 Public. All Rights Reserved.
    Some more...
    DOM
    Added properties DOMElement::$className and DOMElement::$id
    Added properties DOMNode::$isConnected and DOMNameSpaceNode::$isConnected
    Added properties DOMNode::$parentElement and DOMNameSpaceNode::$parentElement
    FFI
    It is now possible to assign FFI\CData to other FFI\CData.
    Meaning CData can now be assigned to structs and fields.
    Opcache
    opcache_get_status()​
    ['scripts'][n]['revalidate'] now contains a Unix timestamp of when the next revalidation of the scripts timestamp is due,
    dictated by the opcache.revalidate_freq INI directive.
    POSIX
    posix_getrlimit() now takes an optional $res parameter to allow fetching a single resource limit.
    posix_isatty() now raises type warnings for integers following the usual ZPP semantics.
    posix_ttyname() now raises type warnings for integers following the usual ZPP semantics and value warnings for invalid file descriptor integers.
    Streams
    Streams can now emit the STREAM_NOTIFY_COMPLETED notification. This was previously not implemented.
    These are not binary-​
    safe at the moment
    because of underlying
    limitations of libxml2.
    This means that the
    property values will be
    cut off at a NUL byte.
    Source:
    https://php.watch/versions/8.3/php-​
    ini-​
    envar-​
    fallback-​
    value-​
    syntax

    View full-size slide

  20. ©2023 Public. All Rights Reserved.
    NEW CLASSES & INTERFACES

    View full-size slide

  21. ©2023 Public. All Rights Reserved.
    New Date exceptions
    🙌
    DateError
    DateObjectError
    DateRangeError
    DateException
    DateInvalidOperationException
    DateInvalidTimeZoneException
    DateMalformedIntervalStringException
    DateMalformedPeriodStringException
    DateMalformedStringException
    Docs at:
    https://www.php.net/manual/en/book.d
    atetime.php

    View full-size slide

  22. ©2023 Public. All Rights Reserved.
    Random Boundaries

    View full-size slide

  23. ©2023 Public. All Rights Reserved.
    Just in case you can't remember the interval notation either
    🤓
    Source: https://curvebreakerstestprep.com/what-​
    is-​
    interval-​
    notation-​
    domain-​
    range-​
    example/

    View full-size slide

  24. ©2023 Public. All Rights Reserved.
    NEW FUNCTIONS

    View full-size slide

  25. ©2023 Public. All Rights Reserved.
    DatePeriod::createFromISO8601String()
    2023-07-01
    2023-07-08
    2023-07-15
    2023-07-22
    2023-07-29

    View full-size slide

  26. ©2023 Public. All Rights Reserved.
    DOM
    DOMElement::getAttributeNames()
    DOMElement::insertAdjacentElement()
    DOMElement::insertAdjacentText()
    DOMElement::toggleAttribute()
    DOMNode::contains()
    DOMNode::getRootNode()
    DOMNode::isEqualNode()
    DOMNameSpaceNode::contains()
    DOMParentNode::replaceChildren()

    View full-size slide

  27. ©2023 Public. All Rights Reserved.
    Intl
    IntlCalendar::setDate()
    IntlCalendar::setDateTime()
    IntlGregorianCalendar::createFromDate()
    IntlGregorianCalendar::createFromDateTime()
    Convenience
    methods to
    cover common
    use-​
    cases

    View full-size slide

  28. ©2023 Public. All Rights Reserved.
    JSON
    json_validate() —
    🙌
    LDAP
    ldap_connect_wallet() — Connect to an LDAP server
    ldap_exop_sync() — Performs an extended operation
    MBString
    mb_str_pad() — Pad a multibyte string to a certain length with another multibyte string

    View full-size slide

  29. ©2023 Public. All Rights Reserved.
    Posix
    posix_sysconf() — Returns system runtime information
    posix_pathconf() — Returns the value of a configurable limit
    posix_fpathconf() — Returns the value of a configurable limit, but for
    file descriptors
    posix_eaccess() — Determine accessibility of a file
    PostgreSQL
    pg_set_error_context_visibility() — Determines the visibility of the
    context's error messages returned by pg_last_error() and
    pg_result_error()

    View full-size slide

  30. ©2023 Public. All Rights Reserved.
    Random
    Random\Randomizer::getBytesFromString()
    Random\Randomizer::nextFloat()
    Random\Randomizer::getFloat()
    Reflection
    ReflectionMethod::createFromMethodName()
    Socket
    socket_atmark() — Determines whether
    socket is at out-​
    of-​
    band mark

    View full-size slide

  31. ©2023 Public. All Rights Reserved.
    Standard
    str_increment() — Increment an alphanumeric string
    str_decrement() — Decrement an alphanumeric string
    stream_context_set_options() — Sets options on the specified
    context
    Zip
    ZipArchive::getArchiveFlag() — Returns the value of a Zip
    archive global flag

    View full-size slide

  32. ©2023 Public. All Rights Reserved.
    NEW GLOBAL CONSTANTS

    View full-size slide

  33. ©2023 Public. All Rights Reserved.
    cURL
    CURLINFO_CAPATH (libcurl >= 7.84.0)
    CURLINFO_CAINFO (libcurl >= 7.84.0)
    CURLOPT_MIME_OPTIONS (libcurl >= 7.81.0)
    CURLMIMEOPT_FORMESCAPE (libcurl >= 7.81.0)
    CURLOPT_WS_OPTIONS (libcurl >= 7.86.0)
    CURLWS_RAW_MODE (libcurl >= 7.86.0)
    CURLOPT_SSH_HOSTKEYFUNCTION (libcurl >= 7.84.0)
    CURLOPT_PROTOCOLS_STR (libcurl >= 7.85.0)
    CURLOPT_REDIR_PROTOCOLS_STR (libcurl >= 7.85.0)
    CURLOPT_CA_CACHE_TIMEOUT (libcurl >= 7.87.0)
    CURLOPT_QUICK_EXIT (libcurl >= 7.87.0)
    CURLKHMATCH_OK (libcurl >= 7.19.6)
    CURLKHMATCH_MISMATCH (libcurl >= 7.19.6)
    CURLKHMATCH_MISSING (libcurl >= 7.19.6)
    CURLKHMATCH_LAST (libcurl >= 7.19.6)
    Intl
    MIXED_NUMBERS (Spoofchecker)
    HIDDEN_OVERLAY (Spoofchecker)

    www.php.net
    PHP: Spoofchecker -
    Manual
    From http://icu-
    project.org/apiref/icu4j/com/ibm/icu/text/Spo
    :SINGLE_SCRIPT_CONFUSABLE: indicates
    that the two strings are visually
    confusable and that they are from the
    same
    scriptMIXED_SCRIPT_CONFUSABLE:
    indicates that the two strings a…

    View full-size slide

  34. ©2023 Public. All Rights Reserved.
    OpenSSL
    OPENSSL_CMS_OLDMIMETYPE
    PKCS7_NOOLDMIMETYPE
    PCNTL
    SIGINFO — (CTRL+T in console)
    PDO_ODBC
    PDO_ODBC_TYPE
    CMS =
    Cryptographic
    Message
    Syntax

    View full-size slide

  35. ©2023 Public. All Rights Reserved.
    Posix
    POSIX_SC_ARG_MAX
    POSIX_SC_PAGESIZE
    POSIX_SC_NPROCESSORS_CONF
    POSIX_SC_NPROCESSORS_ONLN
    POSIX_PC_LINK_MAX
    POSIX_PC_MAX_CANON
    POSIX_PC_MAX_INPUT
    POSIX_PC_NAME_MAX
    POSIX_PC_PATH_MAX
    POSIX_PC_PIPE_BUF
    POSIX_PC_CHOWN_RESTRICTED
    POSIX_PC_NO_TRUNC
    POSIX_PC_ALLOC_SIZE_MIN
    POSIX_PC_SYMLINK_MAX
    Socket
    The following socket options are now defined if
    supported:
    SO_ATTACH_REUSEPORT_CBPF (Linux)
    SO_DETACH_BPF (Linux)
    SO_DETACH_FILTER (Linux)
    TCP_QUICKACK (Linux)
    IP_DONTFRAG (FreeBSD)
    IP_MTU_DISCOVER (Linux)
    IP_PMTUDISC_DO (Linux)
    IP_PMTUDISC_DONT (Linux)
    IP_PMTUDISC_WANT (Linux)
    IP_PMTUDISC_PROBE (Linux)
    IP_PMTUDISC_INTERFACE (Linux)
    IP_PMTUDISC_OMIT (Linux)
    AF_DIVERT (FreeBSD)
    SOL_UDPLITE
    UDPLITE_RECV_CSCOV
    UDPLITE_SEND_CSCOV
    SO_RERROR (NetBSD)
    SO_ZEROIZE (OpenBSD)
    SO_SPLICE (OpenBSD)
    TCP_REPAIR (Linux)
    SO_REUSEPORT_LB (FreeBSD)
    IP_BIND_ADDRESS_NO_PORT (Linux)

    View full-size slide

  36. ©2023 Public. All Rights Reserved.
    Zip
    ZipArchive::ER_DATA_LENGTH (libzip >= 1.10)
    ZipArchive::ER_NOT_ALLOWED (libzip >= 1.10)
    ZipArchive::AFL_RDONLY (libzip >= 1.10)
    ZipArchive::AFL_IS_TORRENTZIP (libzip >= 1.10)
    ZipArchive::AFL_WANT_TORRENTZIP (libzip >= 1.10)
    ZipArchive::AFL_CREATE_OR_KEEP_FILE_FOR_EMPTY_ARCHIVE (libzip >= 1.10)
    ZipArchive::FL_OPEN_FILE_NOW
    ZipArchive::LENGTH_TO_END as default value for ZipArchive::addFile() and ZipArchive::replaceFile()
    ZipArchive::LENGTH_UNCHECKED (libzip >= 1.10)

    View full-size slide

  37. ©2023 Public. All Rights Reserved.
    BACKWARD
    INCOMPATIBLE CHANGES
    (BC BREAKS)

    View full-size slide

  38. ©2023 Public. All Rights Reserved.
    Programs that were very close to overflowing the call stack may now throw an Error when
    using more than zend.max_allowed_stack_size-​
    zend.reserved_stack_size bytes of stack
    (fiber.stack_size-​
    zend.reserved_stack_size for fibers).
    Executing proc_get_status() multiple times will now always return the right value on POSIX
    systems. Previously, only the first call of the function returned the right value. Executing
    proc_close() after proc_get_status() will now also return the right exit code. Previously this
    would return -1. Internally, this works by caching the result on POSIX systems. If the previous
    behaviour is required, it is possible to check the "cached" key in the array returned by
    proc_get_status() to check whether the result was cached.
    Zend Max Execution Timers is now enabled by default for ZTS builds on Linux.
    Uses of traits with static properties will now redeclare static properties inherited from the
    parent class. This will create a separate static property storage for the current class. This is
    analogous to adding the static property to the class directly without traits.
    PHP Core
    If you like your
    project at least a
    bit: Please try
    to avoid using
    traits!
    🙏

    View full-size slide

  39. ©2023 Public. All Rights Reserved.
    Assigning a negative index $n to an empty array will now make sure that the next index is
    $n+1 instead of 0.
    Class constant visibility variance is now correctly checked when inherited from interfaces.
    WeakMap entries whose key maps to itself (possibly transitively) may now be removed during
    cycle collection if the key is not reachable except by iterating over the WeakMap (reachability
    via iteration is considered weak). Previously, such entries would never be automatically
    removed.
    PHP Core
    The DateTime extension has introduced Date extension specific exceptions and errors under
    the DateError and DateException hierarchies, instead of warnings and generic exceptions. This
    improves error handling, at the expense of having to check for errors and exceptions.
    Date

    View full-size slide

  40. ©2023 Public. All Rights Reserved.
    Calling DOMChildNode::after(), DOMChildNode::before(), DOMChildNode::replaceWith() on a node that has no parent is now a
    no-​
    op instead of a hierarchy exception, which is the behaviour demanded by the DOM specification.
    Using the DOMParentNode and DOMChildNode methods without a document now works instead of throwing a
    DOM_HIERARCHY_REQUEST_ERR DOMException. This is in line with the behaviour demanded by the DOM specification.
    Calling DOMDocument::createAttributeNS() without specifying a prefix would incorrectly create a default namespace, placing
    the element inside the namespace instead of the attribute. This bug is now fixed.
    DOMDocument::createAttributeNS() would previously incorrectly throw a DOM_NAMESPACE_ERRNAMESPACE_ERR
    DOMException when the prefix was already used for a different URI. It now correctly chooses a different prefix when there's a
    prefix name conflict.
    New methods and properties were added to some DOM classes. If a userland class inherits from these classes and declare a
    method or property with the same name, the declarations must be compatible. Otherwise, a typical compile error about
    incompatible declarations will be thrown. See the list of new features and new functions for a list of the newly implemented
    methods and properties.
    Command message payloads

    View full-size slide

  41. ©2023 Public. All Rights Reserved.
    C functions that have a return type of void now return null instead of returning the following
    object object(FFI\CData:void) { }
    FFI
    The opcache.consistency_checks INI directive was removed. This feature was broken with the
    tracing JIT, as well as with inheritance cache, and has been disabled without a way to enable
    it since PHP 8.1.18 and PHP 8.2.5. Both the tracing JIT and inheritance cache may modify shm
    after the script has been persisted by invalidating its checksum. The attempted fix skipped
    over the modifiable pointers but was rejected due to complexity. For this reason, it was
    decided to remove the feature instead.
    Opcache

    View full-size slide

  42. ©2023 Public. All Rights Reserved.
    The range() function has had various changes:
    Standard
    A TypeError is now thrown when passing objects, resources, or arrays as the boundary inputs.
    A more descriptive ValueError is thrown when passing 0 for $step.
    A ValueError is now thrown when using a negative $step for increasing ranges.
    If $step is a float that can be interpreted as an int, it is now done so.
    A ValueError is now thrown if any argument is infinity or NAN.
    An E_WARNING is now emitted if $start or $end is the empty string. The value continues to be cast to the value 0.
    An E_WARNING is now emitted if $start or $end has more than one byte, only if it is a non-​
    numeric string.
    An E_WARNING is now emitted if $start or $end is cast to an integer because the other boundary input is a number. (e.g.
    range(5, 'z');).
    An E_WARNING is now emitted if $step is a float when trying to generate a range of characters, except if both boundary
    inputs are numeric strings (e.g. range('5', '9', 0.5); does not produce a warning).
    range() now produce a list of characters if one of the boundary inputs is a string digit instead of casting the other input to
    int (e.g. range('9', 'A');).

    View full-size slide

  43. ©2023 Public. All Rights Reserved.
    Standard
    The file() flags error check now catches all invalid flags. Notably FILE_APPEND was previously silently accepted.
    SNMP
    The type of SNMP class constants are now declared.
    Phar
    The type of Phar class constants are now declared.

    View full-size slide

  44. ©2023 Public. All Rights Reserved.
    DEPRECATED FEATURES

    View full-size slide

  45. ©2023 Public. All Rights Reserved.
    Saner Increment/Decrement operators
    Using the increment operator (++) on empty, non-​
    numeric, or non-​
    alphanumeric strings is now
    deprecated. Moreover, incrementing non-​
    numeric strings is soft deprecated. That means no
    E_DEPRECATED diagnostic is emitted, but this feature should not be used when producing new
    code. The new str_increment() function should be used instead.
    Using the decrement operator (--) on empty or non-​
    numeric strings is now deprecated.
    get_class() / get_parent_class()
    Calling get_class() and get_parent_class() without arguments is now deprecated.

    View full-size slide

  46. ©2023 Public. All Rights Reserved.
    DBA
    Calling dba_fetch() with $dba as the 3rd argument is now deprecated.
    FFI
    Calling FFI::cast(), FFI::new(), and FFI::type() statically is now deprecated.
    Intl
    The U_MULTIPLE_DECIMAL_SEP*E*RATORS constant had been deprecated, using the
    U_MULTIPLE_DECIMAL_SEP*A*RATORS constant instead is recommended.
    The NumberFormatter::TYPE_CURRENCY constant has been deprecated.

    View full-size slide

  47. ©2023 Public. All Rights Reserved.
    LDAP
    Calling ldap_connect() with separate $hostname and $port is deprecated.
    MBString
    Passing a negative $width to mb_strimwidth() is now deprecated.
    Phar
    Calling Phar::setStub() with a resource and a $length is now deprecated. Such calls should be
    replaced by: $phar->setStub(stream_get_contents($resource));

    View full-size slide

  48. ©2023 Public. All Rights Reserved.
    Random
    The MT_RAND_PHP Mt19937 variant is deprecated.
    Reflection
    Calling ReflectionProperty::setValue() with only one parameter is deprecated. To set
    static properties, pass null as the first parameter.

    View full-size slide

  49. ©2023 Public. All Rights Reserved.
    Standard
    The assert_options() function is now deprecated.
    The ASSERT_ACTIVE, ASSERT_BAIL, ASSERT_CALLBACK, ASSERT_EXCEPTION, and
    ASSERT_WARNING constants have been deprecated.
    The assert.* INI settings have been deprecated. See the Changes to INI File Handling page for
    further details.
    SQLite3
    Using exceptions is now preferred, warnings will be removed in the future. Calling
    SQLite3::enableExceptions(false) will trigger a deprecation warning in this version.
    Zip
    The ZipArchive::FL_RECOMPRESS constant is deprecated and will be removed in a future version
    of libzip.

    View full-size slide

  50. ©2023 Public. All Rights Reserved.
    WINDOWS SUPPORT

    View full-size slide

  51. ©2023 Public. All Rights Reserved.
    Minimum supported Windows
    version has been bumped to
    Windows 8 or Windows Server
    2012.

    View full-size slide

  52. ©2023 Public. All Rights Reserved.
    OTHER CHANGES

    View full-size slide

  53. ©2023 Public. All Rights Reserved.

    www.php.net
    PHP: Other Changes -
    Manual
    Core has added the following 8 fields:
    "running" => bool "protected" => bool
    "buffer_size" => int "application_time"
    => float: Total application time, in
    seconds (including collector_time)
    "collector_time" => float: Time spent
    collecting cycles, in seco…

    View full-size slide

  54. ©2023 Public. All Rights Reserved.
    MPOWR IT GmbH
    Enderstr. 94
    01277 Dresden
    Deutschland
    Geschäftsführung:
    Patrick Pächnatz
    Holger Woltersdorf
    Web: https://mpowr.it
    E-​
    Mail: [email protected]
    HRB 43777
    Amtsgericht Dresden
    USt-​
    ID: DE359347772
    THANK YOU!
    Holger Woltersdorf
    CO-​
    Founder & CEO

    View full-size slide