Проблемы с использованием DOTNET из PHP.


Я пытался вызвать сборку .net с PHP через com (используя DOTNET()). Похоже, php находит DLL и правильно инициализирует, но я по какой-то причине не могу видеть/использовать методы. Кто-нибудь знает, как я мог бы это исправить?

Вот php-код, который я использую для вызова класса .net. Когда я называю это, вывод "привет1 привет2". Когда я пытаюсь напрямую вызвать функцию, выполнив $csclass->ModelBuilder("",""), я получаю ошибку сервера 500, указывающую, что она не смог найти нужную функцию.

<?php
echo "hello1";
try{
$csclass = new DOTNET("ModelBuilder, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1208136d23b48dc5",
                      "ModelBuilder.ModelBuilder2");

$class_methods = get_class_methods($csclass);

foreach ($class_methods as $method_name) {
    echo "$method_name\n";
}

} catch (Exception $e) {
    echo 'Caught exception: ',  $e->getMessage(), "\n";
}
echo "hello2";
?>

Вот класс в сборке, которую я пытаюсь вызвать (построен с использованием .net 3.5, подписан строгим именем и зарегистрирован в gacutil):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using OfficeOpenXml;
using System.Runtime.InteropServices;

namespace ModelBuilder
{    
    [ClassInterface(ClassInterfaceType.AutoDual)]
    [ComVisible(true)]
    public class ModelBuilder2
    {
        [ComVisible(true)]
        public Boolean BuildModel(String outputFileLoc,String excelTemplateFile)
        {
            try
            {
                //do stuff
            return true;
        }
        catch (Exception e)
        {                
            return false;
        }
    }

} 
Author: Cheeso, 2012-06-03

1 answers

get_class_methods() не будет работать с объектом класса Dotnet. Эта штука является прокси-сервером, и она ведет себя не так, как обычный php-объект.

Если вы действительно сосредоточены на перечислении методов объекта, то вам нужно изучить возможность реализации IDispatch на вашем.ЧИСТЫЙ объект. Если, однако, ваша главная цель состоит в том, чтобы просто использовать .ЧИСТЫЙ объект, и ваша попытка перечислить методы была просто побочной попыткой диагностировать, почему это не работало, тогда у меня есть некоторые предложения для вас.

  1. Вместо того, чтобы использовать gacutil, подумайте, можете ли вы вставить необходимую библиотеку DLL в каталог php, место, где php.exe проживает. Если php.exe находится в c:\php5\php.exe, скопируйте свою сборку в c:\php5.

  2. Если вы последуете приведенному выше предложению, то.СЕТЕВАЯ сборка не должна иметь строгого имени. Он должен быть строго назван, если вы планируете его GAC. Как я уже сказал, вам не нужно GAC, чтобы загрузить его с помощью php. Если вы скопируете сборка в директорию PHP, затем вы можете использовать неподписанную сборку.

  3. Для ранней разработки и изучения этого используйте программу php.exe из командной строки, а не используйте IIS для запуска php через веб-запрос. Это позволяет вам напрямую просматривать сообщения об ошибках, а не беспокоиться о 500 ошибках из IIS.


Пример

Предположим, что это код C#:

using System;
namespace Ionic
{
    public class MathEx
    {
        System.Random rnd;
        public MathEx ()
        {
            rnd = new System.Random();
        }

        public int RandomEven()
        {
            return rnd.Next()*2;
        }
    }
}

Скомпилируйте его из командной строки, например это:

c:\net3.5\csc.exe /t:library /out:Ionic.MathEx.dll MathEx.cs

Скопируйте сборку в каталог, содержащий php.exe :

copy Ionic.MathEx.dll \php
        1 file(s) copied.

Тогда предположим, что у меня есть php-скрипт с именем mathex.php с этим содержанием:

<?php
$my_assembly = 'Ionic.MathEx'; // name of the dll without the .dll suffix
$clz = new DOTNET($my_assembly, 'Ionic.MathEx');
for ($i=0; $i<5; $i++) {
    echo $i . " " . $clz->RandomEven() . "\n";
}
?>

... и если я запущу его из командной строки следующим образом:

\php\php.exe  mathex.php  

...затем я получаю следующие результаты:

0 -1083602762
1 1535669896
2 -86761710
3 -1204365564
4 459406052

Нота Бене

Я попытался сделать это с помощью сборки, скомпилированной с .NET 4.0, но это не сработало, выдав мне сообщение об ошибке о несоответствии времени выполнения .NET. Нравится это:

Fatal error: Uncaught exception 'com_exception' with message 'Failed to instantiate .Net object
[CreateInstance] [0x8013101b] ' in C:\dev\php\mathEx.php:6
Stack trace:
#0 C:\dev\php\mathEx.php(6): dotnet->dotnet('Ionic.MathEx', 'Ionic.MathEx')
#1 {main}
  thrown in C:\dev\php\mathEx.php on line 6

0x8013101b указывает на несоответствие среды выполнения - версия среды выполнения сборки не соответствует версии среды выполнения приложения, которое пытается загрузить сборку.

Из этого я делаю вывод, что php5 скомпилирован для поддержки .NET 2.0 (который включает в себя 3.0 и 3.5). Версия среды выполнения изменена для .NET 4.0, поэтому сборки, которые вы компилируете с помощью компилятора .NET 4.0 (включая VS2010), не будут использоваться с php5.exe . Обходной путь состоит в том, чтобы просто скомпилировать с помощью .NET компилятор 2.0 или 3.5 (VS2005, vs2008).

 8
Author: Cheeso, 2012-06-03 22:53:19